Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Shell 删除除具有特定扩展名的文件以外的所有文件_Shell_Cygwin_Rm - Fatal编程技术网

Shell 删除除具有特定扩展名的文件以外的所有文件

Shell 删除除具有特定扩展名的文件以外的所有文件,shell,cygwin,rm,Shell,Cygwin,Rm,这将删除以.a或.b结尾的所有文件 $ ls *.a a.a b.a c.a $ ls *.b a.b b.b c.b $ rm *.a *.b 我该如何做相反的事情,删除所有以*.*.结尾的文件,除了那些以*.a和*.b结尾的文件?有一些shell可以做到这一点(我想?),但是,bash在默认情况下不是这样的。如果您正在Cygwin上运行bash,则可以执行以下操作: rm $(ls -1 | grep -v '.*\.a' | grep -v '.*\.b') ls-1(这

这将删除以
.a
.b
结尾的所有文件

$ ls *.a
a.a  b.a  c.a

$ ls *.b
a.b  b.b  c.b

$ rm *.a *.b

我该如何做相反的事情,删除所有以
*.*.
结尾的文件,除了那些以
*.a
*.b
结尾的文件?

有一些shell可以做到这一点(我想?),但是,
bash
在默认情况下不是这样的。如果您正在Cygwin上运行
bash
,则可以执行以下操作:

rm $(ls -1 | grep -v '.*\.a' | grep -v '.*\.b')
  • ls-1
    (这是一个)列出当前目录中的所有文件,每行一个
  • grep-v'.*\.a'
    返回所有不以.a结尾的匹配项
  • grep-v'.*\.b'
    返回所有不以.b结尾的匹配项

您可以在bash中启用扩展全局:

shopt -s extglob
然后您可以使用:

rm *.!(a|b)
删除除以
*.a
*.b
结尾的文件外的所有以
*.a
*.b
结尾的文件

更新:(感谢@mklement0)以下是一种本地化设置
extglob
(不改变全局状态)的方法,方法是在
子shell中执行此操作并使用中间变量:

(shopt -s extglob; glob='*.!(a|b)'; rm $glob)

有时候最好不要坚持用某种方式解决问题。对于“以某种棘手的方式处理某些文件”的一般问题,
find
可能是最好的全方位工具

find . -type f -maxdepth 1 ! -name \*.[ab] -delete

如果要递归到子目录中,请省略
-maxdepth 1

链接的答案包含有用的信息,尽管问题有些含糊不清,答案使用不同的解释

在您的情况下,最简单的方法可能是(简化版的):

  • 注意使用子shell(
    (…)
    )来本地化
    GLOBIGNORE
    变量的设置
  • 分配给
    GLOBIGNORE
    的模式必须分开
这种方法的吸引力在于,您可以在不更改全局状态的情况下使用单个子shell

相比之下,使用
shopt-s extglob
获得单个子shell需要一些技巧:

(shopt -s extglob; glob='*.!(a|b)'; echo $glob)
请注意,必须使用中间变量,如果没有中间变量,命令将中断(因为在执行命令之前将扩展文本glob,此时扩展的globbing语法尚未识别)


警告:使用
GLOBIGNORE
会产生意外的副作用(bug?):

如果将
GLOBIGNORE
设置为任意值,则
*
*.
的路径名扩展将表现为shell选项
dotglob
有效,即使它无效。
换句话说:如果设置了
GLOBIGNORE
,则未被
GLOBIGNORE
中的模式明确豁免的隐藏文件始终由
*
*.
匹配

默认情况下,
dotglob
处于关闭状态,导致
*
不包含隐藏文件(如果未设置
GLOBIGNORE
,默认情况下为true)

如果您还希望在使用
GLOBIGNORE
时排除隐藏文件,请添加以下模式:
*
;应用于这个问题,你会得到:

 (GLOBIGNORE='*.a:*.b:.*'; rm *.*)

相比之下,在打开
extglob
shell选项后使用扩展globing确实尊重
dotglob
选项。

类似用法的可能重复
shopt-u extglob
禁用TKS,希望使用一个变量,以便我可以添加其他不被删除的条件。@HattrickNZ从另一篇文章中看到。在启用
extglob
的情况下,您的bash可能支持这种风格的语法:
rm!(*.a |*.b)
在这种情况下,您可以使用变量。@HattrickNZ事实上,我可以验证这是否有效:
shopt-s extglob;rm_all_but=“*.a |*.b”;rm!($rm_all_,but)
。请记住,
extglob
将保持启用状态……我必须查找
extglob
,感谢您找到了中间变量技术,允许将
shopt-s extglob
和使用扩展glob放在同一行上。如果你把它放在一个子shell中,设置
extglob
会被有效地本地化(没有保持启用状态):
(shopt-s extglob;glob='!(*.a |*.b);rm$glob)
。受@savanto评论的启发,我找到了一种通过子shell本地化设置
extglob
(即不改变全局状态)的方法:
(shopt-s extglob;glob='*.!(a | b)';rm$glob)
-注意中间变量的强制使用。
 (GLOBIGNORE='*.a:*.b:.*'; rm *.*)