如何使用缺少 -exec 的查找递归设置目录权限?

S. *_*ish 5 bash pipe find quoting qnap

我的 Qnap NAS 被一个find缺少-exec参数的命令诅咒,所以我必须通过管道传输某些东西。外壳是:GNU bash,版本 3.2.57(2)-release-(arm-unknown-linux-gnueabihf)

我试图在当前目录的所有子目录(不是文件)上设置 setgid 位。

这不起作用:

find . -type d | xargs chmod g+s $1
Run Code Online (Sandbox Code Playgroud)

使用"$1""$(1)"$("1")等将不能工作。它们都表示chmod正在传递一个包含空格作为两个或多个参数的目录名称(它会输出有关支持哪些参数的标准帮助消息)。

xargs如果我不需要,我不在乎使用;我认为无论如何它都会被长名字窒息,不是吗?

这些及其变体不起作用:

find . -type d | chmod g+s

find . -type d | chmod g+s "$1"
Run Code Online (Sandbox Code Playgroud)

我想过使用awksed注入引号,但我必须认为有一种更简单的方法来做到这一点。人们以前是做什么的-exec?(可悲的是,我可能早在 1995 年左右就知道,但早已忘记了。)

PS:这些目录名称中的许多将包含 Unicode 字符、?符号等。它们最初来自 macOS,这是相当宽松的。也就是说,我可能应该?用 Unicode 字符之类的东西替换所有实例,?这样 Windows 就不会被它们阻塞。但这也需要find对这个残缺软件版本的find.

Gil*_*il' 12

的输出find发出由换行符1分隔的文件名。这不是xargs想要的格式,find也无法生成xargs想要的格式:它将输入解析为空格分隔的项目,\'"用于引用。的某些版本xargs可以采用换行符分隔的输入,但如果您find缺少标准选项,那么您xargs也有可能这样做。

find . -type d | xargs chmod g+s只要您的目录名称不包含空格或\'". 请注意,没有$1: 这对 shell 有意义,但是没有 shell 参与解析 的输出find并将其提供给chmod,只有xargs.

如果您的findhas-print0和您的xargshas -0,您可以使用这些选项来传递以空分隔的文件名,它适用于任意文件名。

find . -type d -print0 | xargs -0 chmod g+s
Run Code Online (Sandbox Code Playgroud)

如果您xargs支持标准选项-I,您可以使用它来指示它将每一行作为一个项目处理,而不是用空格分隔的引号字符串。这可以处理空格,但不能处理\"'或 换行符。

find . -type d | xargs -I {} chmod g+s {}
Run Code Online (Sandbox Code Playgroud)

您可以使用 shell 循环遍历行而不是xargs. 这适用于任何不包含换行符的文件名。

find . -type d | while IFS= read -r line; do chmod g+s "$line"; done
Run Code Online (Sandbox Code Playgroud)

这两种解决方案都只适用于不包含换行符的文件名。find包含换行符的with 文件名的输出是模棱两可的,除了一种解析起来很痛苦的情况:find不会自发地发出多个斜杠,因此如果您//输入要遍历的目录的路径,则可以在输出中识别出这一点。这是一些经过最少测试的代码,它使用这个事实将输出find转换为xargs.

chars=$(printf '\t "'\\\')
{ find .//. -type d; echo .// } | LC_ALL=C sed -n '
s/['"$chars"']/\\&/g
/^\.\/\// {
x
s/\n/\\&/g
p
b
}
H' | LC_ALL=C xargs chmod g+s
Run Code Online (Sandbox Code Playgroud)

1 更准确地说:以换行符结尾(姓氏后面有一个换行符)。

  • @PeterCordes POSIX `xargs` 有 `-I` 但没有 `-d`。BSD 也没有`-d`。`-d` 是一个 GNU 扩展。 (2认同)