对一组文件运行扩展

对一组文件运行扩展

我正在尝试对命令找到的所有文件运行 expand shell 命令find。我尝试过 -exec 和 xargs,但都失败了。有人能解释一下为什么吗?我使用的是 Mac。


find . -name "*.php" -exec expand -t 4 {} > {} \;

这仅创建一个{}包含所有输出的文件,而不是覆盖每个单独的找到的文件本身。


find . -name "*.php" -print0 | xargs -0 -I expand -t 4 {} > {}

这只是输出

4 {}
xargs: 4: No such file or directory

答案1

对于这样的事情,我通常会这样做:

find . -type f | grep php$ | xargs -i expand -t 4 {} > {}

分解如下::
find . -type f从当前目录向下查找所有文件
| grep php$:通过 grep 将结果传输到管道以查找所有以 php 结尾的文件名
| xargs -i expand -t 4 {} > {}:对于每个文件,调用expand -t 4 <file> > <file>

-i请注意, not -Ifor的用法xargs,并且由于通过过滤器,grep因此不需要参数-0

对于大量文件来说,这种方法速度会稍微慢一些,但应该可以按预期工作。

您还可以尝试:

find . -name "*.php" -print0 | xargs -0 -i expand -t 4 {} > {}

再次注意使用-i而不是-I

答案2

find 启动后不会神奇地扩展所有{}实例,只会扩展它在自己的命令行中看到的位置。如果您想在命令中使用 bash 重定向,则需要在 bash shell 命令中使用它,如下所示:

find . -name "*.php" -exec bash -c 'expand -t 4 {} > {}' \;

按照您编写的方式,的输出find . -name "*.php" -exec expand -t 4 {}将被发送到文件{}

在您给出的第二个示例中,find 命令会打印文件列表,然后将其提供给 xargs,这与 find 命令完全无关。xargs通过对输入的每个项目运行一次命令来工作:find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f是一个很好的示例,说明了如何使用它。最后,该命令管道的最后一部分将结果输出到文件{}

需要注意的是,命令管道的每个元素都与其他元素完全独立。如果要在管道中重复使用字符串,则应将其放在 shell 变量中以存储它。例如,您可以按如下方式使用 bash for 循环(额外的复杂性在于正确处理名称中带有空格的文件,就像find -0自动执行的那样):

#!/bin/bash
shopt -s globstar
for f in **; do
  if ! echo $f | grep -i -q .php ; then
    continue
  fi
  expand -t 4 $f > ${f}.ex
  mv ${f}.ex $f
done

您还应该使用临时文件而不是就地编辑。您可能希望分两步完成此操作(即,不要mv首先执行),以防犯错。意外毁掉所有 php 文件会很不幸。

最后,您可以使用 xargs-I stringtoreplace选项。如果您使用-i不带参数的命令,它与 相同-I {},但更难阅读。在这种情况下,您的第二种方法是

find . -name "*.php" -print0 | xargs -0 -I [file] expand -t 4 [file] > [file]

如果您有文件,您可能想要使用-iname而不是-namegrep -i而不是。grep.PHP

相关内容