6 bash shell for-loop escaping find
我正在尝试做类似以下的事情:
for file in `find . *.foo`
do
somecommand $file
done
Run Code Online (Sandbox Code Playgroud)
但命令不起作用,因为$ 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.
任何提示?我很高兴任何解决方法,但我很沮丧,我无法弄清楚这一点.
谢谢,亚历克斯
(嗨马特!)
lhu*_*ath 11
你有很多答案可以解释如何做到这一点; 但为了完成,我将重复并添加:
xargs只对交互式使用有用(当您知道所有文件名都是普通的 - 没有空格或引号时)或与-0选项一起使用时.否则,它会打破一切.
find是一个非常有用的工具; 使用它来管道文件名xargs(甚至用-0)是相当复杂的,因为find可以用它们自己做什么-exec command {} \;或-exec command {} +取决于你想要的东西:
find /path -name 'pattern' -exec somecommand {} \;
find /path -name 'pattern' -exec somecommand {} +
Run Code Online (Sandbox Code Playgroud)
前者运行somecommand同一个参数每个文件递归/path匹配pattern.
后者运行somecommand与尽可能多的参数作为适合在命令行上一次为递归文件中/path那场比赛pattern.
使用哪一个取决于somecommand.如果它可以采用多个文件名参数(例如rm,grep等等),则后一个选项更快(因为您运行的somecommand频率较低).如果somecommand只需要一个参数,那么您需要前一个解决方案.所以看看somecommand的手册页.
更多信息find:http://mywiki.wooledge.org/UsingFind
In bash,for是一个迭代参数的语句.如果您这样做:
for foo in "$bar"
Run Code Online (Sandbox Code Playgroud)
你给for 一个参数迭代(注意引号!).如果您这样做:
for foo in $bar
Run Code Online (Sandbox Code Playgroud)
如果有空格,制表符或换行符(技术上,无论是什么字符),你都要求把它bash的内容bar拆开并撕掉它,IFS并使用该操作的各个部分作为参数. 那不是文件名.假设包含文件名的撕裂长字符串的结果在一堆文件名中存在空格的地方是错误的.正如你刚刚注意到的那样.
答案是:不要使用for,这显然是错误的工具.以上find命令都假设somecommand是可执行文件PATH.如果它是一个bash声明,你将需要这个结构(迭代find输出,就像你尝试过,但安全):
while read -r -d ''; do
somebashstatement "$REPLY"
done < <(find /path -name 'pattern' -print0)
Run Code Online (Sandbox Code Playgroud)
这使用一个while-read循环来读取字符串find输出的一部分,直到它到达一个NULL字节(-print0用于分隔文件名).由于NULL字节不能是文件名的一部分(与空格,制表符和换行符不同),因此这是一种安全的操作.
如果您不需要somebashstatement成为脚本的一部分(例如,它不会通过保留计数器或设置变量或某些变量来更改脚本环境),那么您仍然可以使用find's -exec来运行您的bash语句:
find /path -name 'pattern' -exec bash -c 'somebashstatement "$1"' -- {} \;
find /path -name 'pattern' -exec bash -c 'for file; do somebashstatement "$file"; done' -- {} +
Run Code Online (Sandbox Code Playgroud)
这里,-exec执行bash具有三个或更多参数的命令.
--. bash将它放入$0,你可以在这里放任何你喜欢的东西,真的.{} \;还是{} +分别).文件名(S)结束(S)起来$1(和$2,$3...如果有,当然不止一个).此处bash第一个find命令中的语句以somebashstatement文件名作为参数运行.
这里bash的第二个find命令中的语句运行一个for(!)循环,它遍历每个位置参数(这就是缩减for语法for foo; do- 的作用)并运行一个somebashstatement文件名作为参数.最先之间这里的差别find声明我发现用-exec {} +的是我们只运行一个bash过程,大量的文件名,但还是一个somebashstatement为每个这些文件名.
所有这些也在UsingFind上面链接的页面中得到了很好的解释.
而不是依靠shell来完成这项工作,依靠find来做:
find . -name "*.foo" -exec somecommand "{}" \;
Run Code Online (Sandbox Code Playgroud)
然后文件名将被正确转义,并且永远不会被shell解释.
| 归档时间: |
|
| 查看次数: |
6516 次 |
| 最近记录: |