如何在 Bash 中打开或列出名称与两个模式匹配的所有文件

如何在 Bash 中打开或列出名称与两个模式匹配的所有文件

假设我有一个包含数千个文件的目录;如何打开名称中同时包含字符串“red”和“green”的所有文件?

答案1

find . -type f -name '*red*' -name '*green*'  -exec echo {} +

替换echovigvimless您想要用来打开文件的任何命令。

请注意,某些程序无法在命令行上处理多个文件名。如果您选择的程序是其中之一,请将+行末尾的 替换为\;。这将为每个文件名运行一次命令,而不是只对一长串文件名运行一次。

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 在非文本字符串上会阻塞,并且不支持所有多字节文本编码)。

kshbash -O extglobzsh -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

相关内容