对找到的文件执行命令

有时我们需要针对很多文件运行命令。这可以使用 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 扩展,可能无法在其他版本的 findxargs 中使用。

执行此操作的首选方法是跳过 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