使用STDIN的"gsutil rm"命令

1 投票
2 回答
1094 浏览
提问于 2025-04-17 23:52

我在Linux环境中使用gsutil来管理GCS里的文件。我很喜欢用一个命令

gsutil -m cp -I gs://...

配合其他命令,把标准输入传给gsutil来上传文件;这样我可以保持一个本地的文件列表,记录已经上传的文件,或者生成特定的文件模式来上传并交给它处理。

我想要能用类似的命令

gsutil -m rm -I gs://...

来清理文件。目前,我是先建立一个要删除的大文件列表,然后用下面的代码来运行:

while read line
do
gsutil rm gs://...
done < "$myfile.txt"

这样做比起多线程的“gsutil -m rm...”命令慢得多,而启用-m选项在处理文件时逐个从列表中删除时也没有效果。我还试过直接运行

gsutil -m rm gs://.../* # remove everything
<my command> | gsutil -m cp -I gs://.../ # put back the pieces that I want

但这样会重新复制很多数据,浪费了很多时间;因为数据已经在那儿了,只需要删除一些就行。任何建议都很受欢迎。另外,我在重命名文件方面没有太多灵活性;要不然在上传之前快速重命名就能解决这些问题了。

2 个回答

1

对于有疑问的人,我最后按照Zach Wilt上面提到的方法进行了操作。为了让大家了解,我是在5个文件夹里删除大约几千个文件,总共大约10,000个文件。如果不加“-m”这个选项,删除这些文件要花超过30分钟;而加上“-m”之后,时间缩短到不到30秒。真是飞快!

举个具体的例子:我用这个方法来更新Google Cloud Storage里的文件,使它们和本地文件保持一致。每天我都有一个程序会生成很多增量文件,还有一些是“汇总”的文件。经过一周,增量文件会在本地自动清理,但在GCS里也应该这样做,以节省空间。下面是具体的操作方法:

#!/bin/bash

# get the full date strings for touch
start=`date --date='-9 days' +%x`
end=`date --date='-8 days' +%x`

# other vars
mon=`date --date='-9 days' +%b | tr [A-Z] [a-z]`
day=`date --date='-9 days' +%d`

# display start and finish times
echo "Cleaning files from $start"

# update start and finish times
touch --date="$start" /tmp/start1
touch --date="$end" /tmp/end1

# repeat for all servers
for dr in "dir1" "dir2" "dir3" ... 
do

    # list files in range and build retention file
    find /local/path/$dr/ -newer /tmp/start1 ! -newer /tmp/end1 > "$dr-local.txt"

    # get list of all files from appropriate folder on GCS
    gsutil ls gs://gcs_path/$mon/$dr/$day/ > "$dr-gcs.txt"

    # formatting the host list file
    sed -i "s|gs://gcs_path/$mon/$dr/$day/|/local/path/$dr/|" "$dr-gcs.txt"

    # build sed command file to delete matches
    while read line
    do
        echo "\|$line|d" >> "$dr-del.txt"
    done < "$dr-local.txt"

    # run command file to strip lines for files that need to remain
    sed -f "$dr-del.txt" <"$dr-gcs.txt" >"$dr-out.txt"

    # convert local names to GCS names
    sed -i "s|/local/path/$dr/|gs://gcs_path/$mon/$dr/$day/|" "$dr-out.txt"

    # new variable to hold string
    del=""

    # convert newline separated file to one long string
    while read line
    do
        del="$del$line "
    done < "$dr-out.txt"

    # remove all files matching the final output
    gsutil -m rm $del

    # cleanup files
    rm $dr-local.txt
    rm $dr-gcs.txt
    rm $dr-del.txt
    rm $dr-out.txt

done

你需要根据自己的需求进行修改,但这是一种具体且有效的方法,用于在本地删除文件,然后将这些更改同步到Google Cloud Storage。显然,你需要根据自己的情况进行调整。再次感谢@Zach Wilt。

3

作为一个临时解决方案,因为我们现在没有 -I 这个选项可以用在 rm 命令上,那我们可以在循环中先把所有想要删除的对象放到一个字符串里,然后用 gsutil -m rm 来删除它们。你也可以写一个简单的 Python 脚本,通过 Python 来调用 gsutil 命令,作为一个单独的进程来执行。

进一步扩展你之前的例子,可能可以这样做(声明一下:我的 bash 技能不是很好,而且我没有测试过这个):

objects=''
while read line
do
  objects="$objects gs://$line"
done
gsutil -m rm $objects

撰写回答