"chmod:缺少操作数"在 bash xargs 脚本中



>我在 centos 7 中有一个文件夹,如下所示:

[root@localhost www]# ls -all
-rw-r--r--  1   apache websites     191 Apr 23  2018 robots.txt
drwxrwx---  3 websites websites      38 May 14  2018 functions

我想将这些文件夹和文件权限更改为:

[root@localhost www]# ls -all
-r--------  1   apache apache     191 Apr 23  2018 robots.txt
drx-------  3   apache apache      38 May 14  2018 functions

我尝试了如下 bash 脚本:

find . -group websites -type f -print0 | tee >(xargs -0 chgrp apache) | xargs -0 chown apache | xargs -0 chmod 400
find . -group websites -type d -print0 | tee >(xargs -0 chgrp apache) | xargs -0 chown apache | xargs -0 chmod 500

但是我得到错误:

chmod: missing operand after ‘400’
Try 'chmod --help' for more information.
chmod: missing operand after ‘500’
Try 'chmod --help' for more information.

怎么了? 提前感谢!

当您可以使用|teefind的结果运行循环时,为什么要使用多个级别的间接寻址使事情复杂化,如下所示

while IFS= read -r -d '' file; do
chgrp apache "$file"
chown apache "$file"
chmod 400 "$file"
done < <(find . -group websites -type f -print0)

以及以下目录

while IFS= read -r -d '' dir; do
chgrp apache "$dir"
chown apache "$dir"
chmod 500 "$dir"
done < <(find . -group websites -type d -print0)

您完全可以通过引入一个条件来检查find结果的目录,从而

很好地将其合并为一个
while IFS= read -r -d '' content ; do
chgrp apache "$content"
chown apache "$content"
[[ -d $content ]] && chmod 500 "$content" || chmod 400 "$content"
done < <(find . -group websites -print0)

至于您看到的错误,您的tee的输出被涉及chownxargs消耗,除此之外不可用,因为它没有tee-ed 输出(在标准输出中可用)用于最后一个xargs级别。要使其可用,请制作另一个级别的通行证

find . -group websites -type f -print0 | tee >(xargs -0 chgrp apache) | tee >(xargs -0 chown apache) | xargs -0 chmod 400

或者更好的是,只需使用xargs -0一次,然后在子外壳中一次性运行命令集

find . -group websites -type f -print0 | xargs -0 -I '{}' sh -c 'chgrp apache "{}"; chown apache "{}"; chmod 400 "{}"'

正如Charles Duffy在评论中建议的那样,上述方法可能容易受到攻击,因为我们将文件名替换为脚本文本,而不是将它们作为单独的参数传递到命令行上。可以按以下方式修改该方法(他的建议)

find . -group websites -type f -print0 | xargs -0 sh -c 'for f; do chgrp apache "$f"; chown apache "$f"; chmod 400 "$f"; done' _

find做工作

更简单的解决方案可能如下所示:

find . -group websites 
-exec chown apache:apache -- {} + 
-exec chmod u=rX,g=,o= -- {} +

因为我们使用的是u=rX,它只为已经可执行的目录或文件设置+x,所以我们只能使用一个根本不过滤类型的find命令来执行此操作。

整个模式之所以有效-exec ... {} +是因为向调用的每个命令添加尽可能多的参数,就像xargs一样;使用它,您根本不需要xargs,因此您也不需要tee拆分为多个xargs命令


使tee解决方案发挥作用

原始解决方案的问题在于您正在从xargs -0 chown apache管道到xargs -0 chmod。因为chown,因此xargs -0 chown,没有将输出写入标准输出,所以xargs -0 chmod从未收到任何输入。

当您想从tee写入两个以上的进程时,对除最后一个进程之外的所有进程(甚至所有进程,然后将 stdout 重定向到/dev/null,如果您更关心一致性而不是一点点速度)。

因此:

tee >(xargs -0 chgrp apache) >(xargs -0 chown apache) | xargs -0 chmod 400

。或。。。

tee >(xargs -0 chgrp apache) >(xargs -0 chown apache) >(xargs -0 chmod 400) >/dev/null

(但是当您可以chown apache:apache同时设置所有权和组时,将chgrpchown作为单独的命令运行是愚蠢的;此外,最好在附加一组未知的文件名作为参数之前使用--作为选项结束符号 - 这样做可确保以破折号开头的参数将被视为文件名, 不是作为选项)。

最新更新