sudo cp
和find... -exec sudo cp
产量
/usr/bin/sudo(or find): Argument list too long
我在Travis CI构建输出中遇到此错误。我的.travis.yml文件使用shell脚本(deploy.sh)对branch2的force-app文件夹运行git diff
,输出(数千个文件)是cp
进入新目录:< / p>
sudo cp --parents $(git diff --name-only branch2 force-app/) $DEPLOYDIRECTORY;
错误为两行:
./deploy.sh: line 122: /usr/bin/git: Argument list too long
./deploy.sh: line 122: /usr/bin/sudo: Argument list too long
后续的 find 命令遇到相同的问题。我使用命名约定从git diff查找并复制与每个文件相对应的文件:
for FILE in $GIT_DIFF_FILES; do
if [[ $FILE == *Test.cls ]]; then
find $classPath -maxdepth1 -samefile "$FILE-meta.xml" -exec sudo cp --parents {} $DEPLOY_DIRECTORY +
fi;
done;
再次,我得到了错误:./deploy.sh: line 142: /usr/bin/find: Argument list too long
。
注意:Travis CI正在为此版本运行Ubuntu Linux(Xenial)虚拟环境。
Travis CI自动将堆栈大小设置为 8192 ,将arg max设置为 8388608 。在我的deploy.sh文件中,我ulimit -s 9999999
将每个新版本的堆栈大小更改为 9999999 ,并将arg max更改为 2559999744 。
对于第一个sudo cp
命令,我尝试过:
for loop
tar -cf - -C files... | tar xpf - -C target directory...
git diff ... | xargs cp ...
对于find
命令,我已经尝试过:
find ... | xargs -n 1000 sudo cp ....
find ... -exec cp ...
在本地重现错误后,我发现与少量文件(〜1000个或更少)交互时,我的命令已经可以正常工作。
但是,当cp
的输出大约为 1200-1500个文件或更多时,运行find
和git diff
命令,然后返回:
参数列表太长
此外,仅从我的shell脚本中运行find
或cp
也会返回:
参数列表太长
因此,我对这些命令执行的操作似乎无关紧要。更根本的原因是导致此问题的原因,但是仅当git diff
输出的文件数超过大约1200个文件时。
如何修复cp
和find
命令?
以下是根据我的用例重现此错误的步骤。我使用了VS Code,所以我建议您也尽可能地复制它。请注意,您需要将以下代码中的USERNAME
替换为用户名。
第1步:叉this repo。
第2步:在终端中按照以下步骤操作
cd force-app/main/default
mkdir diff
git checkout -b branch2
cd force-app/main/default/classes
在{strong> myclass.cls 和 myclass.cls-meta.xml 文件的底部添加//comment
。保存更改。
for n in {001..1500}; do cp myclass.cls myclass$n.cls; done
for n in {001..1500}; do cp myclass.cls-meta.xml myclass$n.cls-meta.xml; done
git add .
git commit -m “first commit”
git checkout master
for n in {001..1500}; do cp myclass.cls myclass$n.cls; done
for n in {001..1500}; do cp myclass.cls-meta.xml myclass$n.cls-meta.xml; done
git add .
git commit -m “second commit”
cd .. #back to the sfdx-travisci folder
sudo cp -p $(git diff --name-only branch2 /Users/USERNAME/sfdx-travisci/force-app/main/default/classes) /Users/USERNAME/sfdx-travisci/force-app/main/default/diff
for file in $(sudo cp -p $(git diff --name-only branch2 /Users/USERNAME/sfdx-travisci/force-app/main/default/classes) /Users/USERNAME/sfdx-travisci/force-app/main/default/diff); do if [[ $file == *.cls ]]; then find /Users/USERNAME/sfdx-travisci/force-app/main/default/classes -samefile “$file-meta.xml” -exec sudo cp -p {} /Users/USERNAME/sfdx-travisci/force-app/main/default/diff +; fi; done;
答案 0 :(得分:1)
在大多数操作系统上,命令行长度是有限制的。通常的解决方案不是使用命令行,而是使用管道,最后使用xargs
来获取一批文件作为参数。
例如,您可以使用:
find . | xargs -n 1000 sudo cp ....
在这种情况下,xargs
会一次将参数拆分为1000个文件,并在每个批次中执行sudo cp
。这样,您应该不会有问题(但是在非常长的目录和文件名上)。
如果只想执行一次sudo
,则可能需要移动sudo
内的内容(警告:您可能以root用户的身份访问更多文件,并且应注意管道和重定向是在sudo内部完成,而不是在调用shell中完成。
注意:您还应该将diff
更改为git diff
。
通常我们在-print0
中使用find
,在-0
中使用xargs
,这样文件名中的特殊字符就不会出现问题。 (在POSIX兼容系统中,文件名中禁止使用\U+0000
。
注意:如果可行,您可能希望将带有补丁的错误报告发送给创建原始文件的组(如果该文件不是由您创建的)。我们经常发现这类错误:在特殊情况下失败的命令。