grepのグループマッチングに追加の文字が含まれています。

grepのグループマッチングに追加の文字が含まれています。

Bashで正規表現を使用していくつかのテキストを抽出したかったので、次の簡単な例を試してみることにしました。

echo "abc def ghi" | grep -Po " \K(.*?) "

私は得ることを期待しましたが、驚くべきことに"def""def "最後に余分なスペースがあります)を手に入れました。

grep最後に余分なスペースが含まれている理由とそれを削除する方法に興味があります。別の行を使用して結果を後処理できることはわかっていますが、この問題を解決することに興味があります。

答え1

簡単に言うと:

\K

grepがすべてを維持するようにします。以前\K に変換し、一致に含まれません。これは次に何が起こるかに影響しません後ろにこれ\K()

これで十分です。

" \K(.+)(?= )"

(?= )非キャプチャグループはどこにありますか?

またはより良いかもしれません:

" \K([^ ]+)(?= )"
" \K(\w+)(?= )"

または同様です。

答え2

実行するタスクを実行するBREはsed次のとおりです。

sed 's/ *\(\([^ ]*\) *\)\{[num]\}.*/\2/'

sed...またはGNUおよびBSDバージョンなど、これをサポートするEREを使用して:

sed -E 's/ *(([^ ]*) *){[num]}.*/\2/p'

[num]...どの式でも、グループの最初の文字から始めて一致します。(ここで[num]正の整数は何ですか?)パターンスペースの空白以外の文字を検索し、行の[^ ]*最後まで一致を続けます。

しかし重要なのは、いくつかの一致をグループ化することです。

  • (([^ ]*) *){[num]}- このグループは、空白ではなくグループと次の空白文字の一部/すべてと同じくらい多く発生し、[num]逆参照として使用できます\1
    • {[num]}- パターンが\{[num]\}複数回一致する場合、そのパターンへの唯一の参照は最後のパターンです。したがって、グループが指定されたパターンと複数回一致する場合でも、返される唯一の参照は最後のパターンです。
  • ([^ ]*)- ただし、上記のグループのサブグループは、一致する空白以外の文字のサブセットにのみ一致します\1。このサブグループはで参照できます\2
  • *And .*- これは、パターン空間につながるすべての空白文字とサブ式で一致する項目の後に続くすべての文字と一致します。
  • /\2/- 上記のすべての項目がで参照されているグループに置き換えられます\2

[^ ]*andはブール補数であり、*U[^ ]**一緒に使用すると可能なすべての文字列を記述できるため、上記の正規表現は普遍的です。

あなたの例:

for n in 1 2 3 4
do  echo "abc def ghi" | 
    sed -E "s/ *(([^ ]*) *){$n}.*/\2/"
done | sed -n l

...印刷...

abc$
def$
ghi$
$

現状のままでは、上記で要求された特定のイベントに対して常に空の行を印刷しますが、望ましくない場合は、次のように行を出力から完全に削除できます。

sed -En 's/ *(([^ ]*) *){[num]}.*/\2/;/./p'

さらに一歩進んで、代替をグローバルに適用して、すべての発生項目のみを取得できます[num]。非常に制限的なので、代わりに*これを使用します。[[:space:]]*どんな<space><tab><newline><vertical tab><return>

s=
{   printf "${s:=$(printf '\r\v\t%10s')}"
    seq -s"$s" 100
} | sed -En "s/[${s:=[:space:]}]*(([^$s]*)[$s]*){21}/\2\\
/g;      /[^$s]/s/\n*$//p"

sed上記のビットは、適用される前にprintf ...; seq ...1行を印刷します。たとえば、次のようになります。

\r\v\t          1\r\v\t          2\r\v\t          3\r\v\t...

...など。ただし、上記の結果を適用すると、sed次のようになります。

21
42
63
84

...後にスペースを入れずに数字を印刷します。

関連情報