私はLinuxを学んでいますが、自分で解決できないように思える課題があります。ここにあります:
grepは、1行に4つの数字を含むが4つ以下のファイルから1行をgrepします。
私はこれにどのようにアプローチするかわかりません。特定の数値を検索することはできますが、文字列でその数値を検索することはできません。
この質問を解釈するには2つの方法があります。両方のケースに対処します。行を表示したい場合があります。
たとえば、(1)は1234a56789
を表示しますが、(2)は表示しません。
それ自体が長い数字のシーケンスの一部ではない4桁のシーケンスを含むすべての行を表示する場合、1つの方法は次のとおりです。
grep -P '(?<!\d)\d{4}(?!\d)' file
これは Perl正規表現 を使用します。これはUbuntuの grep
( GNU grep )が-P
を介してサポートします。 12345
のようなテキストには一致しません。また、その一部である1234
や2345
にも一致しません。 ただし、1234
の1234a56789
と一致します。
Perlの正規表現では:
\d
は任意の数字を意味します([0-9]
または[[:digit:]]
と言うのは簡単な方法です)。x{4}
はx
4回と一致します。 ({
}
構文はPerl正規表現に固有のものではありません。grep -E
を介した拡張正規表現にもあります。)\d{4}
は\d\d\d\d
と同じです。(?<!\d)
は、幅がゼロの負の後ろ読みアサーションです。 「\d
が前にない限り」という意味です。(?!\d)
は、幅がゼロの負の先読みアサーションです。 「その後に\d
が続かない限り」という意味です。(?<!\d)
および(?!\d)
は、4桁のシーケンス外のテキストと一致しません。代わりに、より長い一連の数字の一部である場合、(一緒に使用されると)4桁の数字が一致するのを防ぎます。
右端または左端の4桁のサブシーケンスがまだ一致するため、後読みのみまたは先読みのみを使用するだけでは不十分です。
look-behindおよびlook-ahead assertions を使用する利点の1つは、パターンが周囲のテキストではなく、4桁のシーケンスのみと一致することです。これは、色の強調表示(--color
オプションを使用)を使用する場合に役立ちます。
ek@Io:~$ grep -P '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
12345abc789d0123e4
デフォルト Ubuntuでは、各ユーザーは alias grep='grep --color=auto'
ファイル に~.bashrc
を持っています。したがって、grep
で始まる単純なコマンドを実行すると(これは aliases が展開されるとき)、 標準出力 は a terminal であるときに、自動的に色が強調表示されます(これは --color=auto
がチェックするものです)。一致は通常、赤の影で強調表示されます( vermilion に近い)が、斜体の太字で示しています。 スクリーンショットはこちら
また、-o
を使用して、行全体ではなく、一致するテキストのみをgrep
に出力させることもできます。
ek@Io:~$ grep -oP '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
0123
ただし、次の場合:
grep
が-P
をサポートしていないシステム、またはPerl正規表現を使用したくないシステムで実行されるコマンドが必要ですand...次に、代わりに 拡張正規表現 を使用してこれを実現できます。
grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file
これは、それらを囲む4桁の数字と数字以外の文字(または行の先頭または末尾)に一致します。具体的には:
[0-9]
は任意の数字(Perl正規表現の[[:digit:]]
や\d
など)と一致し、{4}
は「4回」を意味します。したがって、[0-9]{4}
は4桁のシーケンスに一致します。[^0-9]
は、0
から9
の範囲にない文字に一致します。 [^[:digit:]]
(またはPerl正規表現では\D
)と同等です。^
は、[
]
括弧内に表示されない場合、行の先頭に一致します。同様に、$
は行末に一致します。|
はorを意味し、括弧はグループ化用です(代数のように)。したがって、(^|[^0-9])
は行の先頭または数字以外の文字に一致し、($|[^0-9])
は行の末尾または数字以外の文字に一致します。したがって、一致は、同時に4桁のシーケンス([0-9]{4}
)を含む行でのみ発生します。
(^|[^0-9])
)の前にand($|[^0-9])
)が続きます。一方、4桁のシーケンスを含むが、4桁を超えるanyシーケンスを含まないすべての行を表示する場合(他のシーケンスのみとは別の行でも) 4桁)、概念的には、1つのパターンには一致するが別のパターンには一致しない行を見つけることが目標です。
したがって、1つのパターンでそれを行う方法を知っていたとしても、2つのパターンに対して別々に matt's 2番目の提案、grep
ingのようなものを使用することをお勧めします。
Perlの正規表現の高度な機能は、それを行う際に大きなメリットを享受しないため、使用しない方がよい場合があります。しかし、上記のスタイルに合わせて、 mattの解決策 の短縮形を以下に示します。\d
の代わりに[0-9]
(および中括弧)を使用します。
grep -P '\d{4}' file | grep -Pv '\d{5}'
[0-9]
を使用しているため、 matt's way はより移植性が高く、grep
がPerlの正規表現をサポートしていないシステムで動作します。 [0-9]
の代わりに[[:digit:]]
(または\d
)を使用し、{
}
を引き続き使用すると、mattの方法の移植性がもう少し簡潔になります。
grep -E '[0-9]{4}' file | grep -Ev '[0-9]{5}'
本当にgrep
コマンドを好む場合
grep
sではありません)...次に使用できます:
grep -Px '(\d{0,4}\D)*\d{4}(\D\d{0,4})*' file
-x
フラグを使用すると、grep
は、行全体が一致する行のみを表示します(行含むではなく)。
\d
と\D
の簡潔さがこの場合の明確さを大幅に向上させると思うので、Perl正規表現を使用しました。ただし、grep
が-P
をサポートしないシステムに移植可能なものが必要な場合は、それらを[0-9]
および[^0-9]
(または[[:digit:]]
および[^[:digit]]
)に置き換えることができます。
grep -Ex '([0-9]{0,4}[^0-9])*[0-9]{4}([^0-9][0-9]{0,4})*' file
これらの正規表現の機能は次のとおりです。
中央では、\d{4}
または[0-9]{4}
は4桁の1つのシーケンスに一致します。これらは複数ある場合もありますが、少なくとも1つ必要です。
左側の(\d{0,4}\D)*
または([0-9]{0,4}[^0-9])*
は、4桁以下で、その後に非数字が続く0個以上の(*
)インスタンスに一致します。ゼロ桁(つまり、何もない)は、「4桁以下」の可能性の1つです。これは(a)空の文字列または(b)任意の文字列endingに一致し、4桁以上のシーケンスを含まない桁。
中央の\d{4}
(または[0-9]{4}
)のすぐ左のテキストは空であるか、数字以外で終わる必要があるため、中央の\d{4}
がそのすぐ左に別の(5番目の)数字がある4桁と一致しないようにします。
右側の(\D\d{0,4})*
または([^0-9][0-9]{0,4})*
は、ゼロ以上の(*
)インスタンスに一致し、その後に4桁以下の数字が続きます(以前と同様に、4、3、2、1、またはまったくない場合もあります)。これは、(a)空の文字列または(b)任意の文字列beginningに一致し、4桁以上のシーケンスを含まない桁。
中央の\d{4}
(または[0-9]{4}
)のすぐ右にあるテキストは空にするか、数字以外で始まる必要があるため、中央の\d{4}
が、そのすぐ右側に別の(5番目の)数字がある4桁と一致しないようにします。
これにより、4桁のシーケンスがどこかに存在し、5桁以上のシーケンスがどこにも存在しないことが保証されます。
この方法で行うことは悪くも間違っていません。しかし、おそらくこの代替案を検討する最も重要な理由は、上記および matt's answer で提案されているように、代わりにgrep -P '\d{4}' file | grep -Pv '\d{5}'
(または同様の)を使用する利点を明確にすることです。
そのようにして、あなたの目標は、あるものを含むが別のものを含まない行を選択することは明らかです。さらに、構文はより単純です(したがって、多くの読者/保守者がより早く理解できるかもしれません)。
これにより、4つの数字が連続して表示されますが、それ以上は表示されません
grep '[0-9][0-9][0-9][0-9][^0-9]' file
^は意味しないことに注意してください
これには問題がありますが、修正方法がわかりません...番号が行末である場合は表示されません。
ただし、このいバージョンはその場合に機能します
grep '[0-9][0-9][0-9][0-9]' file | grep -v [0-9][0-9][0-9][0-9][0-9]
grep
がPerlの正規表現(-P
)をサポートしていない場合、次のシェルコマンドを使用します。
grep -w "$(printf '[0-9]%.0s' {1..4})" file
ここで、printf '[0-9]%.0s' {1..4}
は4回[0-9]
を生成します。この方法は、長い数字があり、パターンを繰り返したくない場合に便利です(4
を自分の数字の数に置き換えるだけです)。
-w
を使用すると、単語全体が検索されます。ただし、1234a
などの英数字文字列に関心がある場合は、パターンの最後に[^0-9]
を追加します。
grep "$(printf '[0-9]%.0s' {1..4})[^0-9]" file
$()
の使用は、基本的に コマンド置換 です。これを確認してください postprintf
がパターンを繰り返す方法を確認してください。
システム内のファイルの実際のファイル名を置き換えることにより、以下のコマンドを試すことができます。grepコマンドのその他の使用法については、 このチュートリアル も確認できます。
grep -E '(^ | [^ 0-9])[0-9] {4}($ | [^ 0-9])'ファイル