用于删除除特定文件和目录之外的所有文件和目录的 Bash 脚本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19782342/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash script to remove all files and directories except specific ones
提问by mario go
I am trying to write a very simple Bash shell script that will cd in a specific directory, it will remove all files and directories except some few selected ones and then cd back to the original dir.
我正在尝试编写一个非常简单的 Bash shell 脚本,它将在特定目录中进行 cd,它将删除除一些选定的文件和目录之外的所有文件和目录,然后 cd 返回到原始目录。
My code is:
我的代码是:
#!/bin/bash
cd /path/to/desired/directory
shopt -s extglob
rm !\(filename1\|filename2\|filename3\) -rf
cd -
I have tried many different ways to write the symbols '(' and '|', with single or double quotes or backslash but nothing worked. Note, that shopt -s extgloband rm !(filename1|filename2) -rfwork fine outside a script.
我已经尝试了许多不同的方式来写符号“(”和“|”,单或双引号或反斜线但是毫无效果。注意,。shopt -s extglob和rm !(filename1|filename2) -rf外部的脚本做工精细。
Probably I am committing a standard and fundamental bash-scripting error that I cannot see, but experience is to come...
可能我犯了一个我看不到的标准和基本的 bash 脚本错误,但经验即将到来......
Any suggestions!? Thanks in advance.
有什么建议!?提前致谢。
回答by Adam Rosenfield
Two problems I can see right off the bat:
我可以立即看到两个问题:
- The
-rfargument tormmust come beforethe filenames - The extglob specifiers
!,(,|and)should notbe escaped with backslashes
- 该
-rf给的说法rm一定要来之前的文件名 - 该extglob符
!,(,|并且)应该不会用反斜杠转义
Try this instead:
试试这个:
rm -rf !(filename1|filename2|filename3)
If it's still not working, remove the -fargument, and you'll get error messages about what's going wrong instead of silently suppressing them. To print out the name of each file removed, you can add the -voption as well.
如果它仍然不起作用,请删除该-f参数,您将收到有关出现问题的错误消息,而不是默默地抑制它们。要打印删除的每个文件的名称,您也可以添加该-v选项。
回答by Aaron Digulla
If you have a recent version of find, then use:
如果您有最新版本的find,请使用:
find . -not -regex "filename1|filename2|filename3" -print
Check the output and replace -printwith -deleteif it prints only the files that you really want to delete.
检查输出并替换-print为-delete它是否仅打印您真正要删除的文件。
If your version of finddoesn't support -delete, use -type f -exec rm "{}" \;
如果您的版本find不支持-delete,请使用-type f -exec rm "{}" \;
Note that this will only delete files. This is important: If you say to keep file xbut that file is in a folder y, then it would ignore xonly to delete it later with the whole folder y.
请注意,这只会删除文件。这很重要:如果您说要保留文件x但该文件在文件夹中y,那么它只会忽略x稍后将其与整个文件夹一起删除y。
To get rid of all empty folders (and this preserving the files you want to keep):
删除所有空文件夹(并保留您要保留的文件):
find . -type d -empty -exec rmdir "{}" \;
(source: How to Find and Delete Empty Directories and Files in Unix)
回答by petrus4
I don't recommend trying to write a rule to exempt specific files. What I would be more likely to do, would be to try and find either a filemask/glob, or some other anchor in the names of the files that you do want to remove, which the files you want to keep, does not have. In most cases, you could probably do that by extension. Unfortunately, because you haven't mentioned what the names of any of the files are, I can't help you more specifically.
我不建议尝试编写规则来免除特定文件。我更有可能做的是尝试在您要删除的文件的名称中找到文件掩码/全局或其他锚点,而您要保留的文件没有。在大多数情况下,您可能可以通过扩展来做到这一点。不幸的是,因为您没有提到任何文件的名称,所以我无法更具体地帮助您。
Something like two (or more) find loops:-
类似于两个(或更多)查找循环:-
find *.mp3 d.mp3 -maxdepth 1 -type f | while read mp3s
do
mv $mp3s ~/d.stuff-to-keep
done
find *.txt d.mp3 -maxdepth 1 -type f while read textfiles
do
rm -v $textfiles
done
If not, look for some other common characteristic of the files. If there isn't one, you might need to rename your files to give yourself one. I always put lots of anchors (seperated name fields, extensions etc) in my filenames, because that way I have a lot of different ways for doing what I need with them. My usual name format is:-
如果没有,请查找文件的其他一些共同特征。如果没有,您可能需要重命名文件以给自己一个。我总是在我的文件名中放置很多锚点(单独的名称字段、扩展名等),因为这样我有很多不同的方法来做我需要的事情。我通常的名字格式是:-
<extension>.+<author>+<year>+<work-name>+<volume-number>+<number-of-volumes>
Plus signs are field seperators, dashes are for spaces, but with no dashes as either first or last characters. All lowercase letters, and no control characters or other non-alphanumerics allowed. As a result, I can cut those up with awk, cut, or whatever else I might want to use, and rename them easily. Putting the extension at the start of the name, also means that ls only needs one flag (-l) to get a perfectly ordered file system.
加号是字段分隔符,破折号表示空格,但没有破折号作为第一个或最后一个字符。所有小写字母,不允许使用控制字符或其他非字母数字。因此,我可以使用 awk、cut 或其他任何我想使用的方法将它们剪掉,并轻松地重命名它们。将扩展名放在名称的开头,也意味着 ls 只需要一个标志 (-l) 即可获得完美有序的文件系统。
If you know how to use your directory structure as a database with the basic POSIX tools, you sometimes won't need to install anything more complicated, in order to do what you want.
如果您知道如何使用基本 POSIX 工具将您的目录结构用作数据库,那么有时您不需要安装任何更复杂的东西来做您想做的事。
You've got a long char limit on filenames in UNIX, as well as tab completion for navigating around long names. Don't be afraid to make liberal use of both of them.
您对 UNIX 中的文件名有一个长字符限制,以及用于在长名称中导航的选项卡完成。不要害怕自由地使用它们。
回答by Mr. BeatMasta
assuming you have files:
假设你有文件:
drwxr-xr-x 2 root root 4096 Feb 1 02:17 a
drwxr-xr-x 2 root root 4096 Feb 1 02:17 b
drwxr-xr-x 2 root root 4096 Feb 1 02:17 c
drwxr-xr-x 2 root root 4096 Feb 1 02:17 d
drwxr-xr-x 2 root root 4096 Feb 1 02:17 e
drwxr-xr-x 2 root root 4096 Feb 1 02:17 f
drwxr-xr-x 2 root root 4096 Feb 1 02:18 nodelete1
drwxr-xr-x 2 root root 4096 Feb 1 02:18 nodelete2
drwxr-xr-x 2 根根 4096 二月 1 02:17 a
drwxr-xr-x 2 根 4096 二月 1 日 02:17 b
drwxr-xr-x 2 根根 4096 二月 1 日 02:17 c
drwxr-xr-x 2 根 4096 二月 1 日 02:17 d
drwxr-xr-x 2 根根 4096 二月 1 日 02:17 e
drwxr-xr-x 2 根 4096 二月 1 日 02:17 f
drwxr-xr-x 2 根 4096 二月 1 02:18 nodelete1
drwxr-xr-x 2 根 4096 Feb 1 02:18 nodelete2
You could do:
你可以这样做:
ls | grep -v "nodel.\+" | xargs rm -rf
ls | grep -v "nodel.\+" | xargs rm -rf
to use advanced regexp syntax to exclude files.
使用高级正则表达式语法来排除文件。
Explanation:
解释:
ls --- lists current directory (ls -d to list only directories)
ls --- 列出当前目录(ls -d 只列出目录)
grep -v --- v flag specifies what NOT TO MATCH + grep allows to write perl style regexp if you supply -P flag
grep -v --- v 标志指定什么 NOT TO MATCH + grep 如果您提供 -P 标志则允许编写 perl 风格的正则表达式
xargs --- applies action "rm -rf" on each of the items
xargs --- 对每个项目应用操作“rm -rf”
回答by Nancy
Try below:
试试下面:
for i in `ls | grep -v "file1\|file2\|file3"` ; do rm -rf $i; done
Good Luck!
祝你好运!

