使用 STDIN 的“gsutil rm”命令

Posted

技术标签:

【中文标题】使用 STDIN 的“gsutil rm”命令【英文标题】:"gsutil rm" command using STDIN 【发布时间】:2014-05-03 19:21:46 【问题描述】:

我在 Linux 环境中使用 gsutil 来管理 GCS 中的文件。我喜欢能够使用命令

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

前面有一些其他命令将 STDIN 传递给 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

但这涉及重新复制大量数据并浪费大量时间;数据已经存在,只需要删除一些。任何想法将不胜感激。另外,我在重命名文件的两端都没有很大的灵活性。否则,在上传之前快速重命名将处理所有这些。

【问题讨论】:

【参考方案1】:

作为一个临时解决方案,因为我们现在没有 rm-I 选项,所以在循环中创建一个包含所有要删除的对象的字符串,然后使用 gsutil -m rm 来删除它?您也可以使用一个简单的 python 脚本来执行此操作,该脚本从 python 中作为一个单独的进程调用 gsutil 命令。

扩展您之前的示例,可能类似于以下内容(免责声明:我的 bash-fu 不是最好的,我还没有测试过):

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

【讨论】:

阅读gsutil rm 的文档页面并没有显示任何关于能够超载这样的多个项目的信息,但我会尽快测试它!如果这行得通,那么你刚刚解决了我的问题。谢谢@Zach Wilt 向 rm 提供这样的参数列表应该可以。在 rm 帮助文档的概要部分中,我们将模板列为 gsutil rm [-f] [-R] url...,这意味着您可以在此处提供任意数量的 url。这在 imo 中并不是特别清楚,因此我们可能应该考虑在文档中使用一种更明显的方式来说明这一点。 工作就像一个魅力;我将为下面的任何人提供一个更强大的示例,但如果可以的话,我会将您的答案标记为答案(还不熟悉 *** 的系统)。谢谢@Zach Wilt。【参考方案2】:

对于任何想知道的人,我最终都做了上面提到的 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。

【讨论】:

以上是关于使用 STDIN 的“gsutil rm”命令的主要内容,如果未能解决你的问题,请参考以下文章

运行包含带有屏幕的 STDIN 重定向的命令

执行远程命令时出现 SSH 错误:“stdin: is not a tty”

使用 Kotlin/Native,我如何执行外部 OS 可执行文件或 $PATH 命令并与其 stdin、stdout 和 stderr 流交互?

捕获通过管道传输到批处理文件的真正 STDIN

Linux学习笔记 -- stdin/stdout 重定向

echo 123456'passwd --stdin liming