对找到的文件执行命令
有时我们需要针对很多文件运行命令。这可以使用 xargs
来完成。
find . -type d -print | xargs -r chmod 770
上面的命令将以递归方式查找相对于 .
(这是你当前的工作目录)的所有目录(-type d
),并对它们执行 chmod 770
。如果 find
没有找到任何文件,-r
选项指定 xargs
不运行 chmod
。
如果你的文件名或目录中包含空格字符,则此命令可能会阻塞; 解决方案是使用以下内容
find . -type d -print0 | xargs -r -0 chmod 770
在上面的示例中,-print0
和 -0
标志指定使用 null
字节分隔文件名,并允许在文件名中使用特殊字符,如空格。这是一个 GNU 扩展,可能无法在其他版本的 find
和 xargs
中使用。
执行此操作的首选方法是跳过 xargs
命令,让 find
调用子进程本身:
find . -type d -exec chmod 770 {} \;
这里,{}
是一个占位符,表示你要在该点使用文件名。find
将分别对每个文件执行 chmod
。
你也可以通过使用将所有文件名传递给 chmod
的单个调用
find . -type d -exec chmod 770 {} +
这也是上述 xargs
片段的行为。 (要单独调用每个文件,可以使用 xargs -n1
)。
第三种选择是让 bash 循环遍历文件名 find
输出列表:
find . -type d | while read -r d; do chmod 770 "$d"; done
这在语法上是最笨重的,但是当你想在每个找到的文件上运行多个命令时很方便。但是,面对具有奇数名称的文件名,这是不安全的。
find . -type f | while read -r d; do mv "$d" "${d// /_}"; done
这将用下划线替换文件名中的所有空格。 (如果前导目录名中有空格,此示例也不起作用。)
上面的问题是 while read -r
期望每行一个条目,但文件名可以包含换行符(并且 read -r
将丢失任何尾随空格)。你可以通过扭转局面来解决这个问题:
find . -type d -exec bash -c 'for f; do mv "$f" "${f// /_}"; done' _ {} +
这样,-exec
以完全正确和便携的形式接收文件名; bash -c
接收它们作为一些参数,可以在 $@
中找到,正确引用等等(当然,脚本需要正确处理这些名称;每个包含文件名的变量都需要用双引号。)
神秘的 _
是必要的,因为 bash -c 'script'
的第一个参数用于填充 $0
。