bash - 如何将 shell 命令应用于嵌套(并且转义不佳)子目录中的许多文件?

标签 bash shell find for-loop escaping

我正在尝试执行以下操作:

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 .如果它可以采用多个文件名参数(如 rmgrep 等),那么后一个选项会更快(因为您运行 somecommand 的频率要低得多)。如 somecommand只需要一个参数,那么你需要前一个解决方案。所以看somecommand的手册页。

更多关于 find : http://mywiki.wooledge.org/UsingFind

bash , for是一个遍历 的语句参数 .如果你做这样的事情:
for foo in "$bar"

你给 for 迭代的参数(注意引号!)。如果你做这样的事情:
for foo in $bar

你在问 bashbar的内容并在有空格、制表符或换行符(技术上,无论 IFS 中的任何字符)的任何地方将其拆开,并使用该操作的片段作为 for 的参数。 那不是文件名 .假设在一堆文件名中产生包含空格的长字符串的结果是错误的。正如你刚刚注意到的。

答案是:别用for ,这显然是错误的工具。以上find命令都假设 somecommandPATH 中的可执行文件.如果是 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 语句。
  • A -- . 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/

    相关文章:

    c - 重定向 shell 中的输入和输出

    c++ vectors - 使用 find(begin, end, term)

    c++ - 在字符串 C++ 中查找子字符串(在 "el"中查找 "hello")

    c++ - 为 STL::map 使用 value_type 数组

    linux - Shell 在 jarsigner 中传递 keystore 路径参数

    bash - 如何创建一个 bash 环境变量,在命令之前添加环境变量前缀?

    Bash:出错时退出并清理

    linux - 将查找结果复制到另一个目录时出现问题

    mysql - 检查mysql是否启动或关闭的shell脚本

    ruby - RVM "ERROR: Unable to checkout branch ."单用户