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が言ったように、スキーマを参照する必要があります。
そして一部は娯楽用です
答え2
ast-open(これを有効にするために使用できるgrep
ast-openの一部として構築されている場合は組み込みgrep
関数)を実装すると、次のように定義できます。ksh93
builtin grep
mygrep
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
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()
どこかに置き、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"
\?
すでにエスケープされている文字列(例:できないものやそうではない\.
もの\*
)を処理する方法について考える必要があります\.*
が、サポートする構文が何であるかを正確に知らない限り、より多くの努力をする価値はありません。