gsutil:参数列表太长

gsutil: Argument list too long

我正在尝试使用以下命令将数千个文件上传到 Google 云存储:

gsutil -m cp *.json gs://mybucket/mydir

但是我得到这个错误:

-bash: Argument list too long

处理此问题的最佳方法是什么?我显然可以编写一个 bash 脚本来迭代不同的数字:

gsutil -m cp 92*.json gs://mybucket/mydir
gsutil -m cp 93*.json gs://mybucket/mydir
gsutil -m cp ...*.json gs://mybucket/mydir

但问题是我事先不知道我的文件名是什么,所以编写该命令并不简单。

有没有办法用 gsutil 本地处理这个问题(我不这么认为,from the documentation),或者有什么方法可以在 bash 中处理这个问题一次列出 10,000 个文件,然后将它们通过管道传输到 gsutil 命令?

如果您的文件名没有换行符,您可以使用 gsutil cp 的能力来读取 stdin,例如

find . -maxdepth 1 -type f -name '*.json' | gsutil -m cp -I gs://mybucket/mydir

或者如果您不确定您的名字是否安全并且您的 findxargs 支持它,您可以这样做

find . -maxdepth 1 -type f -name '*.json' -print0 | xargs -0 -I {} gsutil -m cp {} gs://mybucket/mydir

Eric 的回答应该有效,但另一种选择是依赖 gsutil 的内置通配符,通过引用通配符表达式:

gsutil -m cp "*.json" gs://mybucket/mydir

解释更多:"Argument list too long" 错误来自 shell,它具有用于扩展通配符的有限大小缓冲区。通过引用通配符,您可以防止 shell 扩展通配符,而是 shell 将该文字字符串传递给 gsutil。 gsutil 然后以流方式扩展通配符,即在执行操作时扩展通配符,因此它永远不需要缓冲无限量的扩展文本。因此,您可以对任意大的表达式使用 gsutil 通配符。在对象名称上使用 gsutil 通配符时也是如此,因此例如这将起作用:

gsutil -m cp "gs://my-bucket1/*" gs://my-bucket2

即使 gs://my-bucket1 的顶层有十亿个对象。

这里有一个方法可以做到,使用 xargs 来限制一次传递给 gsutil 的文件数量。空字节用于防止文件名中的空格或换行符出现问题。

printf '%s[=10=]' *.json | xargs -0 sh -c 'copy_all () { 
    gsutil -m cp "$@" gs://mybucket/mydir
}
copy_all "$@"'

这里我们定义了一个函数,用于将文件参数放在gsutil命令中的正确位置。整个过程应该发生处理所有参数所需的最少次数,每次传递尽可能多的文件名参数。

或者您可以单独定义函数,然后 export 它(这是 bash 特定的):

copy_all () { 
    gsutil -m cp "$@" gs://mybucket/mydir
}
printf '%s[=11=]' *.json | xargs -0 bash -c 'export -f copy_all; copy_all "$@"'