grepにはBash-Globbingに類似した検索パターンがあります。

grepにはBash-Globbingに類似した検索パターンがあります。

grep同様のコマンドと一致させるために非常に単純なパターンを使用したいと思います。背景はVM名リストのgrepです。たとえば、VM名のみを一覧表示するコマンドは、名前が「.local」で終わるVMを探しています。

正しいこと:

# virsh list --name | grep '\.local$'

次のようなものを使いたい

# virsh list --name | mygrep *.local

文字クラスや範囲式は必要ありませんが、シェルワイルドカードのデフォルトパターンを適用する必要があります。

  • *0個以上の文字
  • ?1つの役割のみ
  • パターンの始まりと終わりを暗示する文字列の始まりまたは終わりを示す追加のマーカーはありません。
  • ポイントは特別な意味がありません。.

(単純化のために、bashのファイル名ワイルドカードを最初に無視してください)

答え1

カーニバルとして機能

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

==オペレーターが[[...]]いる場所パターンマッチングオペレーター。
引用:https://www.gnu.org/software/bash/manual/bash.html#index-_005b_005b

しかし、@Pankiが言ったように、スキーマを参照する必要があります。


そして一部は娯楽用です

  • function mygrep
      while read --line line
        string match -- $argv[1] $line
      end
    end
    
  • #!/usr/bin/env tclsh
    proc glob_grep {argv} {
        lassign $argv pattern
        while {[gets stdin line] != -1} {
            if {[string match $pattern $line]} {
                puts $line
            }
        }
    }
    glob_grep $argv
    

答え2

ast-open(これを有効にするために使用できるgrepast-openの一部として構築されている場合は組み込みgrep関数)を実装すると、次のように定義できます。ksh93builtin grepmygrep

mygrep() {
  grep -xK "$@"
}

ここで、-K正規表現スタイルをデフォルトの基本正規表現からksh globパターン(bash -O extglobつまり、サポートされているパターンの親セット)に切り替えて、-x正確な一致をオンにします(パターンは行の一部ではなく行全体と一致する必要があります)。

とにかく、次のように呼び出す必要があります。

virsh list --name | mygrep '*.local'

シェルがそれをglobとして解釈するのを防ぐために、文字通り*.local関数mygrepに渡されます。

使用している場合は、zsh次のことができます。

alias mygrep='noglob grep -xK'

引数で拡張されていないグローブの場合は、次のことがmygrepできます。

virsh list --name | mygrep *.local

ただし、これは次のことができないことを意味します。

mygrep *.local ./*.txt

現在のディレクトリのファイル*.localで、globパターンと一致する行を見つけます。.txt

zshでは、配列要素をglobパターンと一致しない要素、${array:#pattern}またはglobパターンと一致する要素でフィルタリングできます${(M)array:#pattern}。次のコマンドを使用して、コマンド出力の空でない行を配列に配置できます${(f)"$(cmd)"}

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

または関数として:

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

このextendedglobオプションを有効にすると、高度なグローバルパターン演算子(大文字と小文字の区別のない一致、間隔のある繰り返し、おおよその一致、否定など)を取得できます。

答え3

pythonsを使ってすばやく何かをしました。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()

どこかに置き、PATH実行可能にしなさい。エッジは少し粗いですが、トリックを実行する必要があります。

コメントで述べたように、ファイル名のシェルが完成するのを防ぐために、パターンを引用する必要があります。

virsh list --name | mygrep '*.local'

答え4

"globbingのような"構文を望んでいたので、どの構文をサポートしたいかはわかりませんが、BREメタ文字を無効にするには、望ましくないすべてのmygrep()BREメタ文字をエスケープするように作成し、に*変更するか、に.*変更してgrepに次のように指示できますあります。ワイルドカード構文と同様の定義を取得するには、行全体を一致させます。?.

$ mygrep() {
    local re
    re=$(sed 's/[.$]/[&]/g; s/?/./g; s/\*/.*/g; s/\^/\\^/g' <<<"$1")
    shift
    printf 'Using grep -x -- "%s"\n' "$re" >&2
    grep -x -- "$re" "$@"
}

$ mygrep '*.local' file
Using grep -x -- ".*[.]local"

\?すでにエスケープされている文字列(例:できないものやそうではない\.もの\*)を処理する方法について考える必要があります\.*が、サポートする構文が何であるかを正確に知らない限り、より多くの努力をする価値はありません。

関連情報