テキストファイルに次のテキストがあります
$ cat test
20180618:
20180619:
20180620:
20180621:
20180622:
20180623:
20180624:
grepを使用して、次のように数値の範囲を見つけようとします。
$ grep 201806{19..21} test
grep: 20180619: No such file or directory
grep: 20180620: No such file or directory
grep: 20180621: No such file or directory
ZSHとbashの両方で上記のエラーが発生します。 grepが文字列をファイルとして検索しているようです。
私は別の方法を試しました。
$ grep 201806* test
zsh: no matches found: 201806*
ZSHでのみこのエラーが発生します。 ZSHでこれを使用する正しい方法は何であり*
、数値範囲に対してgrepにgrepを指示するにはどうすればよいですか?
答え1
ええ、grep
それを治療してください。最初デフォルトでは、パラメータは正規表現として使用されます。
これは意味する
grep {1..9} file
次に展開
grep 1 2 3 4 5 6 7 8 9 file
grep
withは1
他のオペランドと一致する式で呼び出され、これらの他のオペランドはファイル名になると予想されます。
その他のコマンド:
grep 201806* test
これは201806*
ファイル名のワイルドカードパターンで一致しようとします。201806
現在のディレクトリに次の名前で始まるファイルがないため、zsh
シェルはパターンを拡張できず、エラーメッセージを表示しますno matches found
。
Bourneなどの他のシェルでは、パターンがファイル名と一致しない場合は拡張されずに使用されますgrep
。式が201806*
正規表現として扱われると、一致の20180
後にゼロ個以上の6
文字が続きます2018066666
。
代わりに、範囲に一致する正規表現を設定できます。
grep -E '201806(19|20|21)' test
または
grep -E '201806(19|2[01])' test
式の(シフト)を理解する必要があります-E
(この交互にすると拡張正規表現になります)grep
。|
中かっこ拡張を使用して正規表現を構成することもできます。
set -- {19..21}
re=$( IFS='|'; printf '201806(%s)' "$*" )
grep -E "$re" test
これにより、まず位置パラメータと値が範囲内の目的の数値$1
に設定されます。これにより、変数はで区切られた数字で置き換えられる位置に設定されます。$2
$3
re
201806(%s)
printf
%s
|
この呼び出しは正規表現grep
として使用されます。201806(19|20|21)
答え2
grep 201806{19..21} test
シェルを介して次に拡張されました。
grep 20180619 20180620 20180621 test
これは3つのファイルをgrep
見つけることが理解できます。20180619
20180620
20180621
test
次のように変更すると:
grep -e201806{19..21} test
次に、次に展開します。
grep -e20180619 -e20180620 -e20180621 test
で検索できる3つの表現がありますe
。grep
test
またはこれを行うこともできます:
printf '%s\n' 201806{19..21} | grep -f - test
式を複数行入力として渡します(一部の実装ではthisで置き換えるgrep
必要があるかもしれません)。/dev/stdin
-
具体的には、zsh
次のこともできます。
numbers=({19..21} 25 31)
grep -E "201801(${(j:|:)numbers})" test
EREとして使用できるように、パラメータ(j:|:)
拡張フラグを使用して配列要素を(拡張正規表現代替演算子)に関連付けます。|
または、次を使用して配列を正規表現スカラーにバインドすることもできます。
$ typeset -T re numbers '|'
$ numbers=({19..21} 25 31)
$ echo $re
19|20|21|25|31
正規表現には通常、数値範囲一致機能はありませんが、パターンzsh
(extendedglob
機能的に正規表現と同じ)は<x-y>
演算子を使用できます(10進数列のみ)。
print -rl -- ${(M)${(f)"$(<test)"}:#*201806<19-21>*}
答え3
引用符のない文字列は、コマンドを実行する前にシェルによって解釈されます。あなたの場合、試しているコマンドは次に拡張されます。grep 20180619 20180620 20180621 test
$ echo grep 201806{19..21} test
grep 20180619 20180620 20180621 test
1つの回避策は、正規表現の置換を指定することです。
$ grep -E '201806(19|20|21)' test
20180619:
20180620:
20180621:
正規表現を使用して数値範囲を設定できますが、簡単ではありません。バラよりhttps://www.regular-expressions.info/numericranges.html詳しくは
別のオプションは、次のものを使用することです。awk
$ awk -F: '$1>=20180619 && $1<=20180621' ip.txt
20180619:
20180620:
20180621:
ここでは、線を分割し、最初のフィールドを:
目的の$1
範囲と比較します。
答え4
POSIXシェル(いいえ
bash
)とユーティリティ:seq 20180618 20180624 | grep -f - test
-
numgrep '/20180618..20180624/' < test