我正在尝试执行以下操作:
for file in `find . *.foo`
do
somecommand $file
done
但是该命令不起作用,因为 $file 很奇怪。因为我的目录树有蹩脚的文件名(包括空格),我需要转义
find
命令。但明显的转义似乎都不起作用:-ls
给我空格分隔的文件名片段-fprint
没有做得更好。我也试过:
for file in "
找 。 *.foo -ls "; do echo $file; done
- but that gives all of the responses from find in one long line.
任何提示?我对任何解决方法感到高兴,但对我无法弄清楚这一点感到沮丧。
谢谢,
亚历克斯
(嗨,马特!)
最佳答案
你有很多答案可以很好地解释如何去做;但为了完成起见,我将重复并添加:xargs
仅用于交互式使用(当您知道所有文件名都是普通的 - 没有空格或引号时)或与 -0
一起使用时有用选项。否则,它会破坏一切。find
是一个非常有用的工具;使用它来将文件名通过管道传输到 xargs
(即使使用 -0
)也相当复杂,如 find
可以通过 -exec command {} \;
自己完成所有工作或 -exec command {} +
取决于你想要什么:
find /path -name 'pattern' -exec somecommand {} \;
find /path -name 'pattern' -exec somecommand {} +
前者运行
somecommand
与 一个论点对于 /path
中的每个文件递归匹配 pattern
.后者运行
somecommand
与 命令行中适合的尽可能多的参数 一次在 /path
中递归地处理文件匹配pattern
.使用哪一种取决于
somecommand
.如果它可以采用多个文件名参数(如 rm
、 grep
等),那么后一个选项会更快(因为您运行 somecommand
的频率要低得多)。如 somecommand
只需要一个参数,那么你需要前一个解决方案。所以看somecommand
的手册页。更多关于
find
: http://mywiki.wooledge.org/UsingFind在
bash
, for
是一个遍历 的语句参数 .如果你做这样的事情:for foo in "$bar"
你给
for
一 迭代的参数(注意引号!)。如果你做这样的事情:for foo in $bar
你在问
bash
取bar
的内容并在有空格、制表符或换行符(技术上,无论 IFS
中的任何字符)的任何地方将其拆开,并使用该操作的片段作为 for 的参数。 那不是文件名 .假设在一堆文件名中产生包含空格的长字符串的结果是错误的。正如你刚刚注意到的。答案是:别用
for
,这显然是错误的工具。以上find
命令都假设 somecommand
是 PATH
中的可执行文件.如果是 bash
语句,您将需要此构造(迭代 find
的输出,就像您尝试过的那样,但安全):while read -r -d ''; do
somebashstatement "$REPLY"
done < <(find /path -name 'pattern' -print0)
这使用了
while-read
读取部分字符串的循环 find
输出直到达到 NULL
字节(这是 -print0
用来分隔文件名的)。自 NULL
字节不能是文件名的一部分(与空格、制表符和换行符不同)这是一个安全的操作。如果您不需要
somebashstatement
要成为脚本的一部分(例如,它不会通过保留计数器或设置变量等来改变脚本环境),那么您仍然可以使用 find
的 -exec
运行您的 bash
陈述:find /path -name 'pattern' -exec bash -c 'somebashstatement "$1"' -- {} \;
find /path -name 'pattern' -exec bash -c 'for file; do somebashstatement "$file"; done' -- {} +
在这里,
-exec
执行 bash
带有三个或更多参数的命令。--
. bash
将把它放在 $0
,你可以放任何你喜欢的东西,真的。 {} \;
还是 {} +
)。文件名以 $1
结尾(和 $2
, $3
,...当然,如果有多个)。 bash
第一个 find
中的声明此处运行的命令 somebashstatement
以文件名作为参数。bash
第二个 find
中的声明此处的命令运行 for
( ! ) 循环遍历每个位置参数(这就是简化的 for
语法 - for foo; do
- 所做的)并运行 somebashstatement
以文件名作为参数。这里的区别是第一个 find
我用 -exec {} +
展示的声明是我们只运行一个 bash
处理大量文件名但仍然是一个 somebashstatement
为 每个这些文件名。所有这一切也在
UsingFind
中得到了很好的解释。上面链接的页面。
关于bash - 如何将 shell 命令应用于嵌套(并且转义不佳)子目录中的许多文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/753823/