我尝试cp
OSX桌面上符合五位数模式的某些文件。它有效,但我无法理解为什么-n
选项被忽略。如果文件已经存在,我不想覆盖文件。
find ./prefix* -name '[0-9][0-9][0-9][0-9][0-9]' -maxdepth 5 -exec cp -nr {} ./dest \;
即使一个目录已在dest
中,也会复制所有内容。我怎么强迫不覆盖?超级用户This solution表示我可以简单地将dest
中所有内容的权限更改为只读。但我觉得必须有一个理由说明我的实现cp
与man
页面上的实现不一致,因此应该有更好的方法来解决问题。
此外,被覆盖文件的权限为rwxr-xr-x
(如果是你的话,则为0755
。)
答案 0 :(得分:1)
cp
不会做你想做的事。您需要迭代find
的输出。假设您找不到任何路径中的空格或其他特殊字符(如果您这样做,请参见下文):
find ./prefix* -name '[0-9][0-9][0-9][0-9][0-9]' -maxdepth 5 | \
while read dir
do
target=./dest/$(basename $dir)
[ -d $target ] || cp -r $dir ./dest/
done
这是有效的,因为只要while
返回成功,do
就会继续执行done
和read
之间的内容。 find
的输出通过管道传输到read
,因此每次执行read dir
时,它都会从find中读取一行输出并将其分配给dir
变量。
当没有更多行要从find
读取时,read
返回失败并且循环终止。
在循环体内,basename
打印传递给它的路径的最后部分。在这种情况下,5位数。
[ ... ]
是用于运行条件测试的shell术语。 (是的,[
是一个命令!)您可以说test -d ...
而不是[ -d ... ]
。参见例如https://unix.stackexchange.com/questions/99185/what-do-square-brackets-mean-without-the-if-on-the-left了解更多相关信息)
-d ...
将返回成功。如果没有失败。
||
表示或 - 所以foo || bar
仅在bar
失败时执行foo
。
所以循环体基本上说:
let target be "dest/" + the basename of $dir
such a directory exists or copy $dir into dest/
我希望稍微澄清一下。用很少的代码就可以搞很多shell语言。所有这些信息基本上都在bash
联机帮助页中,但可以说是一种更难以访问的格式。
如果find
找到的任何路径都包含空格或其他特殊字符,那么您需要添加引号和其他一些铃声&口哨:
find ./prefix* -name '[0-9][0-9][0-9][0-9][0-9]' -maxdepth 5 -print0 | \
while IFS= read -r -d '' dir
do
target="./dest/$(basename "$dir")"
[ -d "$target" ] || cp -r "$dir" ./dest/
done