Bash globbing 匹配除具有特定扩展名的文件之外的所有文件,适用于包含点字符的文件名

hip*_*ail 10 bash filenames wildcards

我正在用音频文件做一些事情,大多数但不是全部都是 mp3 文件。现在我只想对不是 mp3 文件的文件或没有.mp3扩展名的文件运行一些命令。

我认为自己非常擅长正则表达式,但不太擅长文件通配,这在意想不到的方面有着微妙的不同。

我环顾四周,从其他 SO & SE 的答案中了解到,Bash 已经“扩展了通配符”,可以让我做到这一点:

file ../foo/bar/*.!(mp3)
Run Code Online (Sandbox Code Playgroud)

但是除了形成文件​​扩展名的文件名之外,我的一些文件名中还有点:

../foo/bar/Naked_Scientists_Show_19.10.15.mp3
../foo/bar/YWCS_ep504-111519-pt1_5ej4_41cc9320.mp3_42827d48daefaa81ec09202e67fa8461_24419113.mp3
../foo/bar/eLife_Podcast_19.09.26.mp3
../foo/bar/gdn.sci.080428.bg.science_weekly.mp3
Run Code Online (Sandbox Code Playgroud)

似乎 glob 从第一个点开始匹配,而不是从最后一个点开始。我查看了文档,但似乎它们远不如正则表达式强大。但是我并没有真正理解所有内容,因为我没有在 *nix shell 上花费太多时间。

我是否错过了一些我仍然可以使用 Bash globbing 做到这一点的方法?如果没有,使用 find 或其他工具实现相同目的的方法仍然值得了解。

Sté*_*las 19

*.!(mp3)匹配,foo.bar.mp3因为foo.后面是bar.mp3which is notmp3

你想要!(*.mp3)这里,它匹配任何不以.mp3.

如果你想匹配文件名中包含至少一个.(除领先的一个这将使他们隐藏文件),但不结束.mp3,你可以这样做!(*.mp3|!(*.*))


mur*_*uru 6

还有GLOBIGNORE变量

所述GLOBIGNORE外壳变量可以用来限制该组匹配的图案的文件名。如果GLOBIGNORE设置,GLOBIGNORE则从匹配列表中删除也匹配其中一个模式的每个匹配文件名。如果nocaseglob设置了该选项,GLOBIGNORE则在不考虑大小写的情况下执行与模式的匹配。文件名...总是在GLOBIGNORE设置且不为空时被忽略 。但是,设置GLOBIGNORE为非空值会启用dotglobshell 选项,因此所有其他以“ .”开头的文件名都将匹配。要获得忽略以“ .”开头的文件名的旧行为,请.*在以下情况下禁用“ ”选项中的模式之一GLOBIGNORE. 这dotglobGLOBIGNORE 未设置。

$ touch a.b.mp3 .c.mp3 foo.tgz .bar
$ echo *
a.b.mp3 foo.tgz
$ shopt -s extglob; echo *.!(mp3)
a.b.mp3 foo.tgz
$ GLOBIGNORE='*.mp3'; echo *
.bar foo.tgz
Run Code Online (Sandbox Code Playgroud)