我正在尝试对命令找到的所有文件运行 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 -I
for的用法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
而不是-name
或grep -i
而不是。grep
.PHP