find
我的 Qnap NAS 被一个缺少参数的命令所困扰-exec
,所以我必须通过管道传输某些内容。 shell 是:GNU bash,版本 3.2.57(2)-release-(arm-unknown-linux-gnueabihf)
我试图在当前目录的所有子目录(而不是文件)上设置 setgid 位。
这不起作用:
find . -type d | xargs chmod g+s $1
使用"$1"
、"$(1)"
等$("1")
也不起作用。它们都表明chmod
正在传递一个包含空格作为两个或多个参数的目录名称(它会输出有关支持哪些参数的标准帮助消息)。
xargs
如果不是必须的话我不会用;我觉得长名字还是会让人窒息,不是吗?
这些及其变体不起作用:
find . -type d | chmod g+s
find . -type d | chmod g+s "$1"
我考虑过使用awk
或sed
注入引号,但我必须认为有一种更简单的方法可以做到这一点。人们之前做了什么-exec
? (可悲的是,我可能在 1995 年左右就知道了,但早已忘记了。)
PS:这些目录名称中的各种都会包含Unicode字符、符号?
等。它们最初来自macOS,这是相当宽松的。也就是说,我可能应该?
用 Unicode 字符之类的东西替换所有实例,⁇
这样 Windows 就不会因为它们而卡住。但这也需要find
对这个残件版本的find
.
答案1
的输出发出由换行符1find
分隔的文件名。这不是想要的格式,也无法生成想要的格式:它将其输入解析为空格分隔的项目,并用于引用。某些版本可以采用换行符分隔的输入,但如果您缺乏标准选项,您也可能会这样做。xargs
find
xargs
\'"
xargs
find
xargs
find . -type d | xargs chmod g+s
只要您的目录名称不包含空格或\'"
.请注意,没有$1
: 这对 shell 有意义,但没有 shell 参与解析 的输出find
并将其提供给chmod
, only xargs
。
如果您的find
has-print0
和xargs
has -0
,您可以使用这些选项来传递空分隔的文件名,这适用于任意文件名。
find . -type d -print0 | xargs -0 chmod g+s
如果您xargs
支持标准选项-I
,您可以使用它来指示它将每一行作为一个项目来处理,而不是用空格分隔的带引号的字符串。这可以处理空格,但不能处理\"'
换行符。
find . -type d | xargs -I {} chmod g+s {}
您可以使用 shell 来循环行而不是xargs
.这适用于任何不包含换行符的文件名。
find . -type d | while IFS= read -r line; do chmod g+s "$line"; done
这两种解决方案仅适用于不包含换行符的文件名。 with filenames contains newlines的输出find
是不明确的,除非有一种情况很难解析: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
1 更准确地说:以换行符终止(姓氏后面有一个换行符)。
答案2
你可以用 bash 自己进行递归。就像是:
shopt -s nullglob dotglob
recurse_chmod () (
cd "$1"
for d in ./*/
do
if [ -L "$d" ]; then continue; fi
chmod g+s "$d"
recurse_chmod "$d"
done
)
recurse_chmod .
答案3
您可以告诉 xargs 使用 \0 作为分隔符find . -type d -print0 | xargs -0 chmod g+s
或者
find . -type d | xargs -I{} -d '\n' chmod g+s "{}"
。它将使用 \n 作为分隔符。