复制所有文件但不包括一个文件(BASH命令)

147

我想将一个目录中除了一个名为Default.png的文件之外的所有文件都复制出来。看起来有许多方法可以实现这一点。对你来说,最有效的方法是什么?


为什么你需要跳过那个文件,而不是在复制后直接删除它呢?它已经存在于目标目录中了吗? - Lasse V. Karlsen
1
是的,一个同名文件已经存在于目标目录中。 - Joe Cannatti
1
@LasseV.Karlsen:或者你可能想节省复制它的时间,如果它是一个大文件的话。我对此很感兴趣,但是要排除一个目录而不是一个文件。 - Nikana Reklawyks
9个回答

190

应该如下:

cp -r !(Default.png) /dest
如果将内容复制到当前文件夹中的一个嵌套文件夹中(在下面的示例中称为example),那么您还需要省略该目录:
cp -r !(Default.png|example) /example

20
这会产生以下结果: -bash: !: 事件未找到 - Joe Cannatti
你是将文件复制到从中复制的文件夹嵌套的文件夹中吗? - Jonathan Holloway
55
如果已被禁用,这需要使用 shopt -s extglob 才能工作。 - Barry Kelly
5
看起来,根据@BarryKelly的描述,OS X需要使用shopt -s extglob。有了它,它就可以完美运行了。 - Kat
2
在Bash上多年,竟然不知道!()...太棒了!对于那些像我一样觉得是时候学习/复习Bash的人,这里是与此问题/答案相关的链接:shopt/extglobthe pattern - Brandt
一开始我并没有完全理解如何使用这个命令:cp -r $src_path/!($file) $dest_path,但实际上它相当于 cp $src_path/* $dest_path/ --exclude $file,如果 cp 命令有这样的参数的话。 - mazunki

96

rsync 长期以来一直是我用来替代 cp/scp 的工具:

rsync -av from/ to/ --exclude=Default.png

-a, --archive               archive mode; equals -rlptgoD (no -H,-A,-X)
-v, --verbose               increase verbosity

如果我想排除两个不同的文件,我该如何使用它? - Pulkit Bansal
支持多个 --exclude= 参数。如果您正在同步目录,请不要忘记 -r 参数。 - Rian Sanderson
请注意,它还会复制隐藏文件(例如.git),如果存在相同的文件,则会覆盖它们。 - Islam Murtazaev
当/root/jenkins_api/*中没有文件时,此"rsync -aP --exclude=backup /root/jenkins_api/ /root/jenkins_api/backup"无法工作。是否有解决方法可以在未找到文件时跳过? - Youssef Boudaya

67

如果 src/ 目录下只包含文件,那就简单了:

find src/ ! -name Default.png -exec cp -t dest/ {} +

如果src/有子目录,这个命令会省略它们,但会复制它们内部的文件。
find src/ -type f ! -name Default.png -exec cp -t dest/ {} +

如果src/下有子目录,则不会递归到子目录中:
find src/ -type f -maxdepth 1 ! -name Default.png -exec cp -t dest/ {} +

5
对我来说这是最好的,因为似乎 OS X 没有启用 glob 功能。 - Joe Cannatti
6
@Max \; 每个文件都会执行一次该命令。 + 一次运行该命令并同时将所有文件名传递给它(受命令行长度限制)。 总的来说,+ 更加高效。 - John Kugelman

3
cp `ls | grep -v Default.png` destdir

6
这样做比你想要的更容易产生错误。 - Dennis Williamson
好的@DennisWilliamson,你能解释一下为什么吗? - arthur.sw
1
@arthur.sw 首先,它没有考虑到文件名中有空格的情况。就像许多与 shell 相关的事情一样,存在许多失败的边缘情况。95% 以上的时间,这些东西都能正常工作。只需要注意其中的注意事项。文件名中的空格会使得使用 shell 从简单变得痛苦。 - Will Hartung
另一个原因是由于正则表达式中没有锚点并且点号没有转义,导致它也会匹配例如 myDefaultXpng.OLD 这样的文件名。 - Dennis Williamson

1

2022年1月更新:

这是最简单的方法(并不复杂)。

首先,创建一个"temp"文件夹

mkdir temp

其次,将您原始文件夹中的所有文件复制到"temp"文件夹中:

“-R”标志可以精确地复制包括“符号链接”在内的所有文件

cp -R originalFolder/. temp/

第三步,从“temp”文件夹中删除“Default.png”
rm temp/Default.png

最后,将"temp"文件夹中的所有文件复制到您的目标文件夹中:
cp -R temp/. destinationFolder/

此外,这是不需要"temp"文件夹的最短路径:
cp -R originalFolder/!(Default.png) destinationFolder/

1

I'd just do:

cp srcdir/* destdir/ ; rm destdir/Default.png

除非文件很大,否则请使用例如。
find srcdir -type f/ |grep -v Default.png$ |xargs -ILIST cp LIST destdir/

5
第一个命令不符合OP的要求。如果destdirsrcdir中都存在Default.png,它将用srcdir中的替换destdir中的,并删除复制的Default.png。相反,OP想要保留已经存在于destdir中的Default.png - SnowFrog
3
默认.png已经存在于目标目录中,你的解决方案不会起作用。 - Iman Mohamadi

0

以下脚本对我有效

cp -r `ls -A | grep -v 'skip folder/file name'` destination

-1
# chattr +i /files_to_exclude
# cp source destination
# chattr -i /files_to_exclude

-3

使用Shell的扩展参数与正则表达式

cp /<path>/[^not_to_copy_file]* .

除了not_to_copy_file之外,所有内容都将被复制。

如果有任何问题,请指明!


3
欢迎来到SO。不幸的是,您的答案不正确。括号表达式([...])包含要匹配的一组字符,而前导的 ^ 将导致匹配所列字符的补集。在以下示例中,将不会列出任何文件:touch not_to_copy_file to_copy_file; ls [^not_to_copy_file]*,因为所有以以下任何一个字符开头的文件名都将被排除:_cefilnopty - rtx13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接