grep 具有类似 Bash-Globbing 的搜索模式

Eri*_*ich 7 grep bash wildcards

我想使用一个非常简单的模式与grep类似命令匹配。背景是 grep 虚拟机名称列表,例如仅列出虚拟机名称的命令,我在其中查找名称以“.local”结尾的虚拟机

正确的是:

# virsh list --name | grep '\.local$'
Run Code Online (Sandbox Code Playgroud)

我想用类似的东西

# virsh list --name | mygrep *.local
Run Code Online (Sandbox Code Playgroud)

不需要字符类或范围表达式,但应该应用 shell 通配符的基本模式:

  • *零个或多个字符
  • ?仅针对一个角色
  • 字符串的开始或结束没有额外的标记,这是由模式的开始和结束暗示的
  • 点没有特殊含义.

(为简单起见,请忽略 bash 首先对文件名进行通配)

Sté*_*las 7

通过 ast-open 的实现grep(也是作为 ast-open 的一部分构建grepksh93if 的内置函数,您可以使用 启用它builtin grep),您可以将您的定义为mygrep

mygrep() {
  grep -xK "$@"
}
Run Code Online (Sandbox Code Playgroud)

where将正则表达式风格从默认的基本正则表达式切换为 ksh glob 模式(例如-K支持的模式的超集),并打开精确匹配(模式必须匹配整行,而不是行的任何部分)。bash -O extglob-x

无论如何,您需要将其调用为:

virsh list --name | mygrep '*.local'
Run Code Online (Sandbox Code Playgroud)

为了防止 shell 将其解释*.local为 glob,因此它会按字面意思传递给您的mygrep函数。

如果使用zsh,您可以执行以下操作:

alias mygrep='noglob grep -xK'
Run Code Online (Sandbox Code Playgroud)

对于不在 的参数中扩展的 glob mygrep,然后能够执行以下操作:

virsh list --name | mygrep *.local
Run Code Online (Sandbox Code Playgroud)

但这意味着您不能执行以下操作:

mygrep *.local ./*.txt
Run Code Online (Sandbox Code Playgroud)

*.local.txt当前目录的文件中查找与 glob 模式匹配的行。

在 zsh 中,您可以将数组元素过滤为与 glob 模式不匹配的元素${array:#pattern}或与 glob 模式匹配的元素${(M)array:#pattern}。您可以使用 将命令输出的非空行放入数组中${(f)"$(cmd)"},因此在这里您可以将两者结合起来:

pattern=*.local
print -rC1 -- ${(M)${(f)"$(virsh list --name)"}:#$~pattern}
Run Code Online (Sandbox Code Playgroud)

或者作为一个函数:

cmdglobline() print -rC1 -- ${(M)${(f)"$("$@[2,-1]")"}:#$~1}
cmdglobline '*.local' virsh list --name
Run Code Online (Sandbox Code Playgroud)

您可以启用该extendedglob选项以获得更高级的全局模式运算符(例如不区分大小写的匹配、间隔重复、近似匹配、否定...)。


Pan*_*nki 6

python我很快用s做了一些东西fnmatch.filter

#!/usr/bin/env python3
import fnmatch
import sys

def main():
    try:
        pattern = sys.argv[1]
    except IndexError:
        print('mygrep: No pattern supplied', file=sys.stderr)
        sys.exit(1)

    results = fnmatch.filter([_.rstrip('\n') for _ in sys.stdin.readlines()], pattern)
    for line in results:
        print(line)

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

将其放在您的某个位置PATH,使其可执行。应该可以解决这个问题,尽管边缘有点粗糙。

正如评论中提到的,您还需要引用该模式以避免 shell 完成文件名。

virsh list --name | mygrep '*.local'
Run Code Online (Sandbox Code Playgroud)


gle*_*man 6

作为 bash函数

mygrep() {
    local pattern=$1 line
    while IFS= read -r line; do
        if [[ $line == $pattern ]]; then
            printf '%s\n' "$line"
        fi
    done
}
Run Code Online (Sandbox Code Playgroud)

==其中的运算符是[[...]]模式匹配运算符。
参考: https: //www.gnu.org/software/bash/manual/bash.html#index-_005b_005b

但是,正如 @Panki 所说,你需要引用该模式


还有一些,仅供娱乐