Linuxには、次の行を含むファイルがあります。
(memberOf=CN=Group1)(memberOf=CN=Group2)(memberOf=CN=Group3)(memberOf=CN=Group4)
私の目標は、その行のグループのリストを埋めることです。たとえば、次のようになります。
Group1
Group2
Group3
Group4
答え1
with pcregrep
( P
erlC
互換R
正規E
表現grep
):
pcregrep -io1 '\(memberOf=CN=(.*?)\)'
または直接使用してくださいperl
。
perl -lne 'print $1 while /\(memberOf=CN=(.*?)\)/gi'
(ここでは、LDAP属性名として使用されているか、-i
フラグは大文字と小文字を区別しません。)i
grep
実装がそのオプションをサポートしている場合-P
(grep
PCREサポートでビルドするときにGNUがサポートするように)、非標準オプションもサポートする可能性が高く、-o
次のことができます。
grep -iPo '\(memberOf=CN=\K.*?(?=\))'
他の実装は出力キャプチャグループをサポートしていないため、ここでおよびのプレビュー\K
演算子は、およびが出力(memberOf=CN=
に)
含まれていないことを示すために使用されます。grep
pcregrep
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"
答え3
この解決策はかなり似ています@bxm
が、sed
pureの代わりに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