来自此find
命令的文件路径
find . -printf "%p \n"
不要转义不常见的字符(空格、反斜杠、双引号...)。
该-ls
选项确实打印转义路径,但它只是将 的输出添加ls -dils
到 的输出之前printf
。
我需要一个高效的命令,因此运行额外的命令ls
没有帮助,打印出所有额外的字符也没有帮助。
还有其他(优雅的)方法来输出转义路径吗find
?
答案1
通常,您希望使用find -exec
对所有文件名运行命令,或者find -print0
将名称通过管道传递给某个可以读取由 nul 字节分隔的条目的命令(例如xargs -0
)。
如果你确实想要带引号的字符串,Bash 有几个选项可以做到这一点:
$ find -exec bash -c 'printf "%s\n" "${@@Q}"' sh {} +
'./single'\''quote'
'./space 1'
$'./new\nline'
'./double"quote'
$ find -exec bash -c 'printf "%q\n" "$@"' sh {} +
./single\'quote
./space\ 1
$'./new\nline'
./double\"quote
这确实需要额外调用 shell,但可以使用一次 exec 处理多个文件名。
关于保存权限位(不是 ACL),你可以这样做(在 GNU find 中):
find -printf "%#m:%p\0" > files-and-modes
这将输出带有权限、冒号、文件名和 nul 字节的条目,例如:。它会0644:name with spaces\0
不是转义任何内容,而是按原样打印文件名(除非输出到终端,在这种情况下至少换行符会被破坏。)
您可以使用 Perl 脚本读取结果:
perl -0 -ne '($m, $f) = split/:/, $_, 2; chmod oct($m), $f; ' < files-and-modes
或者勉强在 Bash 中,请参阅评论:
while IFS=: read -r -d '' mode file ; do
# do something useful
printf "<%s> <%s>\n" "$mode" "$file"
chmod "$mode" "$file"
done < files-and-modes
据我测试,它适用于换行符、引号、空格和冒号。请注意,我们需要使用空格以外的其他内容作为分隔符,因为IFS=" "
如果任何名称包含尾随空格,设置将删除它们。
答案2
有了zsh
,你可以这样做:
print -r -- ./**/*(.D:q)
.
相当于-type f
,D
包括像find
will 这样的隐藏文件,以及:q
用于引用(使用zsh
-style 引用,我无法判断这是否是您期望的引用类型)。
您可以获得不同风格的引用:
$ print -r -- ./**/*(.D:q)
./$'\200' ./a\ b ./é ./\"foo\" ./It\'s\ bad ./$'\n'
$ files=(./**/*(.D))
$ print -r -- ${(q)files}
./$'\200' ./$'\n' ./a\ b ./é ./\"foo\" ./It\'s\ bad
$ print -r -- ${(qq)files}
'./�' './
' './a b' './é' './"foo"' './It'\''s bad'
$ print -r -- ${(qqq)files}
"./�" "./
" "./a b" "./é" "./\"foo\"" "./It's bad"
$ print -r -- ${(qqqq)files}
$'./\200' $'./\n' $'./a b' $'./é' $'./"foo"' $'./It\'s bad'
(�
是我的终端模拟器为不可打印的 \200 字节显示的占位符)。
在这里,如果您希望能够以可恢复的方式存储权限,只需执行以下操作:
find . -type f -printf '%m\0%p\0' > saved-permissions
要恢复(假设 GNU xargs
):
xargs -r0n2 -a saved-permissions chmod
然而,这将为chmod
每个文件运行一次调用,这是非常低效的。您可能想使用chmod
内置的shell,zsh
如下所示zmodload zsh/files
:
zmodload zsh/files
while IFS= read -rd '' mode && IFS= read -rd '' file; do
chmod $mode $file
done < saved-permissions
答案3
我找到了一个更简单的解决方案:
find -exec echo \'{}\' \;
我们可以使用它来管道到任何其他程序:
find -exec echo \'{}\' \; | xargs ls
或者我们可以简单地使用任何命令而不是 echo 并添加任意数量的参数:
find -exec mv \'{}\' somewhereelse \;
不要忘记echo
首先进行测试。
最后一个不起作用因为 mv 在访问文件之前不会删除引号,所以请改用管道:
find -exec echo mv \'{}\' somewhereelse \;| bash
答案4
为什么不转义每个字符?然后它适用于任何东西(ls、rm、echo 等):
find -name *.txt | sed -E 's/(.)/\\\1/g' | xargs ls
(您可能需要将其适应-exec
形式,以便变得更有效)