bash xargs脚本中的“ chmod:缺少操作数”

时间:2018-12-27 08:36:45

标签: bash

我在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.

出什么问题了? 预先感谢!

2 个答案:

答案 0 :(得分:3)

当您只需对|的结果进行如下循环时,为什么使用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的输出被xargs所涉及的chown占用,并且除此以外不可用,因为它不是{{1 }}-ed(在标准输出中可用)到tee的最后一级。要使其可用,请再上一级通行证

xargs

或更妙的是,只需使用find . -group websites -type f -print0 | tee >(xargs -0 chgrp apache) | tee >(xargs -0 chown apache) | xargs -0 chmod 400 一次,然后在子外壳中一次运行即可运行一组命令

xargs -0

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

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

答案 1 :(得分:1)

离开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 apachexargs -0 chmod进行管道传输。因为chown以及xargs -0 chown都没有向stdout写输出,所以xargs -0 chmod从未收到任何输入。

当您要从tee写两个以上的进程时,请对除最后一个之外的所有(甚至所有它们)使用进程替代(然后甚至将它们全部替代),然后将stdout重定向到{{1 }},如果您更关心一致性而不是一点点速度。

因此:

/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 同时设置所有权和组时,同时运行chgrpchown作为单独的命令是很愚蠢的;而且,最好使用{{1 }}作为选项结尾符号,然后附加一组未知的文件名作为参数-这样做可以确保以破折号开头的参数将被视为文件名,而不是选项。)