繰り返しなしで、文字列から区切り文字の間の部分文字列を複数回取得します。

繰り返しなしで、文字列から区切り文字の間の部分文字列を複数回取得します。

この問題の解決策を見つけるために、あちこちを見つけましたが、見つかりませんでした。

私はそれをqstat -x長い仕事情報のリストを渡すために使用します。出力はqstat -xXML形式です。私が探している部分文字列は2つの明示的な区切り文字<Output_Path></Output_Path>。以下は、qstat -x機密情報が削除されたいくつかの出力例です。

<Data><Job><Job_Id>4382.xxxxxxxx.xx.xxxxxxx</Job_Id><Job_Name>r053_x.xxMx.xxR_400k_neos2.pbs</Job_Name><Job_Owner>[email protected]</Job_Owner><job_state>H</job_state><queue>default</queue><server>xxxxxxxx.xx.xxxxxxx</server><Checkpoint>u</Checkpoint><ctime>1466396941</ctime><Error_Path>xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r053_x.xxMx.xxR_400k_neos2/r053_x.xxMx.xxR_400k_neos2.pbs.e4382</Error_Path><Hold_Types>u</Hold_Types><Join_Path>n</Join_Path><Keep_Files>n</Keep_Files><Mail_Points>a</Mail_Points><mtime>1466423857</mtime><Output_Path>xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r053_x.xxMx.xxR_400k_neos2/r053_x.xxMx.xxR_400k_neos2.pbs.o4382</Output_Path><Priority>0</Priority><qtime>1466396941</qtime><Rerunable>True</Rerunable><Resource_List><cput>9999:59:59</cput><nodect>1</nodect><nodes>1:ppn=12:gpus=1</nodes><walltime>2400:00:00</walltime></Resource_List><comment>Not Running: Not enough of the right type of nodes are available</comment><submit_args>r053_x.xxMx.xxR_400k_neos2.pbs</submit_args><fault_tolerant>False</fault_tolerant><job_radix>0</job_radix><submit_host>xxxxxxxx.xx.xxxxxxx</submit_host></Job><Job><Job_Id>4396.xxxxxxxx.xx.xxxxxxx</Job_Id><Job_Name>0R_20k_neos2.pbs</Job_Name><Job_Owner>[email protected]</Job_Owner><job_state>H</job_state><queue>default</queue><server>xxxxxxxx.xx.xxxxxxx</server><Checkpoint>u</Checkpoint><ctime>1466606895</ctime><Error_Path>xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r061_x.xxMx.xxR_20k_neos2/0R_20k_neos2.pbs.e4396</Error_Path><Hold_Types>u</Hold_Types><Join_Path>n</Join_Path><Keep_Files>n</Keep_Files><Mail_Points>a</Mail_Points><mtime>1466609370</mtime><Output_Path>xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r061_x.xxMx.xxR_20k_neos2/0R_20k_neos2.pbs.o4396</Output_Path><Priority>0</Priority>

<Output_Path>sumの各繰り返しの間に存在するすべての部分文字列を取得したいと思います</Output_Path>。つまり、文字列がある場合

<Output_Path>xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r061_x.xxMx.xxR_20k_neos2/0R_20k_neos2.pbs.o4396</Output_Path><Output_Path>xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r053_x.xxMx.xxR_400k_neos2/r053_x.xxMx.xxR_400k_neos2.pbs.o4382</Output_Path>

返すコマンドが欲しい

xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r061_x.xxMx.xxR_20k_neos2/0R_20k_neos2.pbs.o4396
xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r053_x.xxMx.xxR_400k_neos2/r053_x.xxMx.xxR_400k_neos2.pbs.o4382

または

xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r061_x.xxMx.xxR_20k_neos2/0R_20k_neos2.pbs.o4396 xxxxxxxx.xx.xxxxxxx:/data/xxxxxxxx/xxxxxxxxxxx/summer2016/relax/r053_x.xxMx.xxR_400k_neos2/r053_x.xxMx.xxR_400k_neos2.pbs.o4382

ただし、遅いループを使用せずにこれを行う必要がありますforawk、およびgrepのバリアントを試してみましたが、sed動作する項目が見つかりませんでした。

どんなアイデアがありますか?

答え1

以下を試してください。

xmlstarlet sel -t -v //Output_Path -nl data.xml

答え2

システムのgrepがPCREをサポートしている場合は、次のことができます。

$ echo 'aaa string1 bbb aaa string2 bbb aaa string3 bbb' | 
  grep -oP '(?<=(aaa|bbb) )\w*?(?= (aaa|bbb))'
string1
string2
string3

または、より一般的な周囲のスペースを処理する必要がある場合

$ echo 'aaa string1 bbb aaa string2 bbb aaa string3 bbb' |
  grep -oP '(aaa|bbb)\s+\K\w*?(?=\s+(aaa|bbb))'
string1
string2
string3

答え3

次の構造に満足している場合:

string1
string2
string3

私は単に区切り文字を改行に置き換えました。次のようなものがあなたを近づけるでしょう:

sed "s/\(aaa\)\|\(bbb\)/\n/g" test.txt

編集する

以下の@clkが指摘したように、最初の答えは二重改行を提供することができます。次に変更します。

sed "s/\(\s\)\?aaa\(\s\)\?/bbb/g" test.txt | sed "s/b*//g"

私に譲ってください:

 string1 string2 string3

入力をパイピングするときにも機能します。たとえば、次のようになります。

echo 'aaa string1 bbb aaa string2 bbb aaa string3 bbb' | sed "s/\(\s\)\?aaa\(\s\)\?/bbb/g" | sed "s/b*//g"

あまり美しい回答は迅速で汚れており、あなたが要求した形式を提供します。

答え4

ただsedを使用してください(-r拡張正規表現フラグを使用)

echo "aaa string1 bbb aaa string2 bbb aaa string3 bbb" | sed -r 's/(aaa|bbb) ?//g'

商品を返す

string1 string2 string3 

-vEtrとgrepを使用してこのバージョンを入手することもできます(次を含む)。

echo "aaa string1 bbb aaa string2 bbb aaa string3 bbb" | tr ' ' '\n'| grep -vE '(aaa|bbb|^$)'

商品を返す

string1
string2
string3

tr空白文字を改行文字に置き換えます。 grep -vE正規表現(「E」)を使用し、一致する行(「v」)を除外します。

3番目のバージョンはsed(フラグなし)とgrep(以前のバージョンと同じ)を使用します。

echo "aaa string1 bbb aaa string2 bbb aaa string3 bbb" | sed 's/\s/\n/g' | grep -vE '(aaa|bbb|^$)'

trの代わりにsedを使用して、バージョン2とほぼ同じことを行います。

編集:^$不要な改行文字を返さないように、grep検索文字列にも追加されました。

Edit2:OPを変更したようです。上記の答えは元の質問に対する答えです。以下に役立つスクリプトを作成しました。 http://pastebin.com/uKWAGE0Y

関連情報