假设我有一个包含数千个文件的目录;如何打开名称中同时包含字符串“red”和“green”的所有文件?
答案1
find . -type f -name '*red*' -name '*green*' -exec echo {} +
替换echo
为vi
、gvim
或less
您想要用来打开文件的任何命令。
请注意,某些程序无法在命令行上处理多个文件名。如果您选择的程序是其中之一,请将+
行末尾的 替换为\;
。这将为每个文件名运行一次命令,而不是只对一长串文件名运行一次。
xdg-open
就是这样一个命令。它会检测要求打开的文件类型,然后使用系统默认程序(如果您覆盖了默认程序,则使用您的首选程序)打开该文件。如果它无法识别文件的类型,它会询问您用什么打开它。
像这样使用它find
有点有用,但同时又有点烦人。尝试一下,您就会明白为什么(您会看到许多窗口打开,一个接一个......每个匹配的文件名一个)。
find . -type f -name '*red*' -name '*green*' -exec xdg-open {} \;
顺便说一句,如果您想查找匹配的文件*red*
或者 *green*
,您必须使用括号来指定“and”( -a
) 和“or”( -o
) 运算符的优先级。顺便说一句,当您find
使用上面的多个谓词运行时,默认运算符是 a -a
,即谓词在逻辑上通过 AND 组合在一起。
括号对 shell 也有特殊含义,因此必须进行反斜杠转义,以便将它们传递给 find 命令而不是由 shell 解释。
find . -type f \( -name '*red*' -o -name '*green*' \) -exec echo {} +
将此读作“常规文件 AND(文件名与‘*红色*’或‘*绿色*’匹配的文件名)”
答案2
和zsh
:
set -o extendedglob # best in ~/.zshrc
ls -ld -- *green*~^*red*
glob~
运算符用于除了(并不是)。^
是为了不是。所以组合是不是不是, 所以和。 IOW,匹配文件green
名中的文件,除了那些做的不是包含red
。
使用否定运算符的替代方案^
(也需要extendedglob
):
ls -ld -- ^(^*green*|^*red*)
除了不包含绿色或不包含红色的文件之外的所有内容。
要还包含隐藏文件,请添加(D)
glob 限定符。
您还可以使用 glob 限定符将文件名与正则表达式进行匹配,并且使用setopt rematchpcre
,您可以使这些正则表达式 PCRE,其中您可以使用前瞻运算符来实现和:
re() {
setopt localoptions rematchpcre
[[ $REPLY =~ $1 ]]
}
ls -ld -- *(e['re "^(?=.*green).*red"'])
或者:
re() {
setopt localoptions rematchpcre
[[ $REPLY =~ $RE ]]
}
RE='^(?=.*green).*red'; ls -ld -- *(+re)
(需要注意的是 PCRE 在非文本字符串上会阻塞,并且不支持所有多字节文本编码)。
与ksh
或bash -O extglob
或zsh -o kshglob
ls -ld -- !(!(*green*)|!(*red*))
!(pattern)
相当于的扩展全局运算ksh
符。zsh
^pattern
你还可以这样做:
ls -ld -- @(*green*red*|*red*green*)
但这并不能推广到任何模式。例如,对于包含abc
和的文件bcd
,您需要@(*abc*bcd*|*abcd*|*bcd*abc*)
, 来进行文件匹配???
和*x*
, @(x??|?x?|??x)
...
和ksh93
ksh93
有一些和通配运算符:
ls -ld -- @(*green*&*red*)
或者使用它的增强的正则表达式(与 glob 运算符一起引入~(A:...)
):
ls -ld -- ~(A:.*green.*&.*red.*)
您还可以perl-like
在以下位置使用前瞻运算符ksh93
:
ls -ld -- ~(P:(?=.*green).*red.*)
答案3
(假设您正在寻找文件名字包含两个都字符串“红色”和字符串“绿色”)
=~
要毫无意义地使用 bash 使用正则表达式匹配运算符来测试文件名的“红色”和“绿色” :
for f in *
do
[[ $f =~ red && $f =~ green ]] && echo Bash: yes: "$f" || echo Bash: no: "$f"
done
要使用标准 shell 语法,使用case
和 glob 来查找相同的文件:
for f in *
do
case "$f" in
*green*red*|*red*green*) echo Case: yes: $f;;
*) echo Case: no: $f;;
esac
done
更简单的是,使用 shell 的通配符:
printf "Glob: %s\n" *green*red* *red*green*
示例运行:
$ touch a b aredgreenb agreenredb agreenbred aredbgreen red green redgreen greenred
$ for f in *
> do
> [[ $f =~ red && $f =~ green ]] && echo Bash: yes: "$f" || echo Bash: no: "$f"
> done
Bash: no: a
Bash: yes: agreenbred
Bash: yes: agreenredb
Bash: yes: aredbgreen
Bash: yes: aredgreenb
Bash: no: b
Bash: no: green
Bash: yes: greenred
Bash: no: red
Bash: yes: redgreen
$ for f in *
> do
> case "$f" in
> *green*red*|*red*green*) echo Case: yes: $f;;
> *) echo Case: no: $f;;
> esac
> done
Case: no: a
Case: yes: agreenbred
Case: yes: agreenredb
Case: yes: aredbgreen
Case: yes: aredgreenb
Case: no: b
Case: no: green
Case: yes: greenred
Case: no: red
Case: yes: redgreen
$ printf "Glob: %s\n" *green*red* *red*green*
Glob: agreenbred
Glob: agreenredb
Glob: greenred
Glob: aredbgreen
Glob: aredgreenb
Glob: redgreen
答案4
很简单,假设该open
命令可以处理多个参数:
open *red* *green*
编辑:抱歉,我正在阅读问题作为打开(名称中带有红色的文件)和(名称中带有绿色的文件);我的错。
以下使用 extglob 并避免在名为 的文件的情况下重复计数redgreenred
:
$ shopt -s extglob # turn on extended globbing
$ printf "extglob: %s\n" @(*green*red*|*red*green*)
extglob: agreenbred
extglob: agreenredb
extglob: aredbgreen
extglob: aredgreenb
extglob: greenred
extglob: redgreen
extglob: redgreenred
$ shopt -u extglob # turn off extended globbing