假设我有以下目录树:
.
├── 11
├── 111
├── 112
├── 1121
├── 113
├── 11a
├── 11a1
├── 1a1
├── 1a2
├── 1aa1.png
├── 2a1
├── a.
├── a1a
├── a1a.jpg
├── a2a
├── aa
├── -aa
├── aa.gif
├── aa.jpg
├── aa.png
├── aa.tiff
├── a.exe
├── a.gif
├── a.html
├── a.jpg
├── a.png
├── a.tiff
├── b2
├── b2a
├── ba.gif
├── ba.jpg
├── ba.png
├── ba.tiff
├── b.html
├── cb1.png
├── d.gif
└── sub1
├── d.gif
└── sub2
所以,如果我想匹配 . ($PWD) 但是带有“.jpg”扩展名的文件,我执行以下操作:
ls !(*.jpg)
但它输出:
11 1121 11a1 1aa1.png a1a aa.gif a.exe a.png b2a ba.tiff d.gif
111 113 1a1 2a1 a2a aa.png a.gif a.tiff ba.gif b.html .gif
112 11a 1a2 a. aa aa.tiff a.html b2 ba.png cb1.png
sub1:
. .. d.gif sub2
我想排除 sub1 及其所有内容(甚至目录),即:
sub1: . .. d.gif sub2
我可以排除使用:
GLOBIGNORE='sub1'
在 ls 之前,但是如果我有更多具有不同名称的目录会发生什么?
有没有办法做到这一点?
答案1
一定要有壳吗bash
?通过 ZSH 和EXTENDED_GLOB
set,我们可以将glob 表达式(.)
限定为纯文件:()
.
$ PS1='%% ' zsh -f
% setopt EXTENDED_GLOB
% mkdir foo && cd foo
% touch nope.jpg
% mkdir sub1
% touch asdf
% print ^*.jpg
asdf sub1
% print ^*.jpg(.)
asdf
%
答案2
带走解决方案:
ls -pd !(*.jpg) | grep -Ev /$
细节
您的 glob 模式不会下降到子目录中。ls
作用:如果您在命令行上传递一个目录,它会显示该目录的内容。
替换ls
为echo
:
$ echo !(*.jpg)
或者,一个(几乎)等效的解决方案:告诉ls
不要进入目录。
$ ls -d !(*.jpg)
回答评论中的问题:“如何使用 ls 命令仅列出文件而不列出文件夹?”有几种选择:
仅列出目录的简短方法是:
echo */
因此,也许,仅列出文件而不列出目录的答案可能会使用grep -v
$ ls -p | grep -Ev /$
$ find . -maxdepth 1 ! -type d
请注意,find 将列出点文件(隐藏文件)。并且find . -type d
(也)不会遵循符号链接。
或者实用的(posix)循环:
$ for f in * ; do if [ -f "$f" ] ; then echo "$f" ; fi ; done
当然,否定展开的具体解决方案应该是这样的:
$ ls -pd !(*.jpg) | grep -Ev /$
11
111
112
1121
113
11a
11a1
1a1
1a2
1aa1.png
2a1
a.
a1a
a2a
aa
aa.gif
aa.png
aa.tiff
a.exe
a.gif
a.html
a.png
a.tiff
b2
b2a
ba.gif
ba.png
ba.tiff
b.html
cb1.png
d.gif
笔记:
选项 -p 与 grep 一起可以识别目录,请查看 ls 手册页:
-p, --文件类型, --indicator-style=文件类型
答案3
您可以将 的输出通过管道传输ls
到grep
过滤器中,例如:
ls * | grep -v "jpg"
返回所有不包含字符串“jpg”的匹配项。 (该grep -v
标志反转匹配,返回不包含指定字符串的每一行。)
答案4
我可以在 ls 之前排除使用: GLOBIGNORE='sub1' ,但是如果我有更多具有不同名称的目录会发生什么?
来自Bash 参考手册, GLOBIGORE 是:
以冒号分隔的模式列表,定义文件名扩展要忽略的文件名集。如果与文件名扩展模式匹配的文件名也与 GLOBIGNORE 中的模式之一匹配,则会将其从匹配列表中删除。模式匹配遵循 extglob shell 选项的设置。