Linux - ファイル行で特定のパターンのすべての発生を検索します。

Linux - ファイル行で特定のパターンのすべての発生を検索します。

Linuxには、次の行を含むファイルがあります。

(memberOf=CN=Group1)(memberOf=CN=Group2)(memberOf=CN=Group3)(memberOf=CN=Group4)

私の目標は、その行のグループのリストを埋めることです。たとえば、次のようになります。

Group1

Group2

Group3

Group4

答え1

with pcregrep( PerlC互換R正規E表現grep):

pcregrep -io1 '\(memberOf=CN=(.*?)\)'

または直接使用してくださいperl

perl -lne 'print $1 while /\(memberOf=CN=(.*?)\)/gi'

(ここでは、LDAP属性名として使用されているか、-iフラグは大文字と小文字を区別しません。)i

grep実装がそのオプションをサポートしている場合-PgrepPCREサポートでビルドするときにGNUがサポートするように)、非標準オプションもサポートする可能性が高く、-o次のことができます。

grep -iPo '\(memberOf=CN=\K.*?(?=\))'

他の実装は出力キャプチャグループをサポートしていないため、ここでおよびのプレビュー\K演算子は、およびが出力(memberOf=CN=)含まれていないことを示すために使用されます。greppcregrep

POSIXユーティリティを使用すると、ほぼ同じことができます。

sed -n '
  /([mM][eE][mM][bB][eE][rR][Oo][fF]=[Cc][Nn]=\([^)]*\))\(.*\)/ {
    s//\
\1\
\2/
    s/.*\n\(.*\n\)/\1/
    P;D
  }'

文字列がシェルスカラー変数に格納されていて、結果のグループをシェル配列変数に保存する場合は、シェルを使用して次のことをzsh実行できます。

set -o extendedglob

string='(memberOf=CN=Group1)(memberOf=CN=Group2)(memberOf=CN=Group3)(memberOf=CN=Group4)'
groups=()

: ${string//(#ib)[(]memberOf=CN=([^)]#)[)]/${groups[$#groups+1]=$match[1]}}

またはGNUから入手してくださいgrep

groups=(
  ${(0)"$(
    print -rN -- $string |
      grep -ziPo '\(memberOf=CN=\K.*?(?=\))'
  )"}
)

Bash 4.4+と同じ:

readarray -td '' groups < <(
  printf '%s\0' "$string" |
    grep -ziPo '\(memberOf=CN=\K.*?(?=\))'
) && wait "$!"

答え2

Raku(以前のPerl_6)の使用

raku -ne 'put $/.join("\n") if m:g/\(memberOf\=CN\= <(.*?)> \)/;'

または

raku -ne 'put $/.join("\n") if m:g/<?after \(memberOf\=CN\= > (.*?) <?before \) > /;'

簡単に言えば、例1は<(…)>Rakuに一致区切り文字を使用して正規表現エンジンにを削除するように指示します<(.*?)>。実施例2は、<?after "pattern1" >肯定的な予測と<?before "pattern2" >肯定的な予測を使用して、それらの間のすべてを分離する。大文字と小文字を区別しないことが重要な場合は、m:g( 'match-global')をm:g:i( 'match-global case-insensitive')に変更してください。

入力例:

(memberOf=CN=Group1)(memberOf=CN=Group2)(memberOf=CN=Group3)(memberOf=CN=Group4)

出力例(1):

Group1
Group2
Group3
Group4

または出力例(2):

Group1 Group2 Group3 Group4

OPにサンプル行に似た複数行を含むファイルがあると仮定すると、すべての出力を1行に返すのが妥当である可能性があります。上記の例のいずれかについて、各行ごとのキャプチャが1行ずつ返されるように単純に変更します(上記の出力2)$/.join("\n")$/

最後に、OPは「グループ」リストの位置情報をエンコードできます(たとえば、左側のサブグループ#、右側の親グループ#)。この場合、一致を削除して次のようにcomb()表示する方が合理的です。.pairs

raku -ne '.raku.say for .comb(/<?after \(memberOf\=CN\= > (.*?) <?before \) > /).pairs;' 

0 => "Group1"
1 => "Group2"
2 => "Group3"
3 => "Group4"

https://docs.raku.org/言語/regexes
https://raku.org

答え3

この解決策はかなり似ています@bxmが、sedpureの代わりに1つの手順を使用しますgrep

grep -Eo '\(memberOf=CN=[^()]*\)' |
sed 's/(memberOf=CN=\(.*\))/\1/' 

入力する:

(memberOf=CN=Group1)(memberOf=CN=Group2)(memberOf=CN=Group3)(memberOf=CN=Group4)
(memberOf=CN=GroupA1)
(memberOf=CN=GroupA2)(memberOf=CN=GroupA3)
(memberOf=CN=GroupA4)
(rememberOf=CN=GroupX1)(memberOf=CN=GroupX2)
(numberOf=CN=GroupX4)
(memberOf=CN=GroupB1)(memberOf=CN=GroupB2)(memberOf=CN=GroupB3)(memberOf=CN=GroupB4)

出力:

Group1
Group2
Group3
Group4
GroupA1
GroupA2
GroupA3
GroupA4
GroupX2
GroupB1
GroupB2
GroupB3
GroupB4

の出力は次の入力grepに表示されます。sed

(memberOf=CN=Group1)
(memberOf=CN=Group2)
(memberOf=CN=Group3)
(memberOf=CN=Group4)
...

sedその後、その出力を取得して先行と(memberOf=CN=末尾を削除します)

このコードは、次の行でより多くの内容をワイルドカードとして追加することで、より一般化できますsed

grep -Eo '\(memberOf=CN=[^()]*\)' |
sed 's/.*=\(.*\))/\1/'

答え4

この問題を解決する方法はいくつかあります。ここでは、広く利用可能な機能を使用し、grep読みやすくすることに焦点を当てたソリューションがあります。

入力がどのようにそこに到達するかを言っていないので、パイプだとします。ファイル入力に適応するのは簡単です。

echo "(memberOf=CN=Group1)(memberOf=CN=Group2)(memberOf=CN=Group3)(memberOf=CN=Group4)" \
  | grep -Eo "[(]memberOf=CN=[^)]+" \
  | grep -Eo "[^=]+$"

これは2つの段階で行われる。

(memberOf=CN=somethingまず、終了せずにすべてのパターンを抽出します)。これは第2段階で重要です。これは「無料」なので、第2段階の作業が簡単になります。このパターンに合わない入力文字列は無視されるため、必要な文字列が他の場所に埋め込まれている状況でも機能する必要があります。

=次に、行の終わりから始めて、逆さまに作業しているのではなく、すべての項目を一致させます。これはmemberOf=CN=文字列の一部を削除する効果があります。

入力の大文字と小文字が保証できない場合は、i最初のフラグに追加しますgrep

注意点:エスケープがあるか値にある)場合、期待どおりに機能しません。=CN

関連情報