我编写了一个 shell 脚本来访问目录中的所有文件/tmp
。然而,有一条错误消息说
/bin/touch: Argument list too long
。问题的原因是什么?
#!/bin/bash
dayNo=1
while test $dayNo -le 200
do
touch `find /tmp/`
sleep 86000
done
答案1
/tmp
你的文件太多了不适合一次在命令行上显示所有名称(如果任何路径中有空格,您拥有的版本也是不安全的)。
好消息是,find
可以安全、正确地为您执行此操作:
find /tmp -exec touch -c '{}' +
将像以前一样找到所有文件,然后touch
根据每次需要运行尽可能多的文件来运行多次。
find
的-exec
选项接受一个命令来运行匹配的文件并替换路径{}
。+
意味着它一次对多个文件运行该命令,或者对每个文件\;
运行一次。touch
正如评论中所指出的,-execdir touch -c '{}' \;
这里严格来说更安全,尽管它可能会慢一些,并且在单用户系统上没有太多好处。它通过首先切换到每个子目录,然后每次仅针对该目录中的文件运行命令来避免某些竞争条件。该-execdir
选项是非标准扩展,但受支持GNU,自由BSD,开放BSD,网络BSD, 和操作系统 find
s;其他商业Unices一般没有它。我不确定您正在使用什么,但如果适用,请考虑上述内容。
答案2
shell 将反引号中表达式的结果替换到该行中。但是系统对命令的参数列表的长度有限制。因此,如果 /tmp 中有几千个文件,它会尝试创建一个包含数千个名称作为参数的命令。这失败了。
有几种方法可以更轻松地做到这一点。发现本身可以运行命令。大多数现代版本将允许您拆分它并运行多个单独的touch
命令,每个命令都在限制之下。
find /tmp -exec touch {} +
答案3
问题中反引号调用的主要问题是,首先 find 命令列出 /tmp 下的所有文件,然后将该(巨大)列表作为参数传递给touch
,这对于单次调用来说太多了。如果文件名包含空格、换行符、分号、& 符号、管道字符或类似字符,也会出现问题。
最好使用这个结构:
find /tmp -type f -exec touch -c '{}' +
该find
命令递归地列出/tmp
.
-type f
告诉 find 仅选择常规文件
该-c
选项可防止touch
触摸创建不存在的文件。
看来您在示例中省略了一些逻辑,但如果您只想执行 200 次,您可以尝试以下操作:
#!/bin/bash 天号=1 测试 $dayNo -le 200 时 做 查找 /tmp -type f -exec touch -c '{}' + 睡眠 86000 天号=$(表达式 1 + ${天号}) 完毕