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
或者如果您不确定您的名字是否安全并且您的 find
和 xargs
支持它,您可以这样做
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 "$@"'
我正在尝试使用以下命令将数千个文件上传到 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
或者如果您不确定您的名字是否安全并且您的 find
和 xargs
支持它,您可以这样做
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 "$@"'