ループせずに1つの文字列から区切り文字間の部分文字列を複数回取得する

ループせずに1つの文字列から区切り文字間の部分文字列を複数回取得する

私はこれに対する解決策を探し回ったが、見つけることはできなかった。

私は、qstat -xジョブ情報の長い文字列を渡すために を使用しています。 からの出力はqstat -xXML 形式です。探している部分文字列は、<Output_Path>と という2 つの明示的な区切り文字の間にあります</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>とのすべての反復の間にあるすべての部分文字列を取得したい</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

しかし、低速ループを使用せずに実行する必要があります。 、、forのバリエーションを使用してみましたが、機能するものは見つかりませんでした。awkgrepsed

何か案は?

答え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 が指摘しているように、私の最初の回答では改行が 2 つある可能性があります。次のように変更します。

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 

tr と grep を使用したこのバージョンもあります ( を使用-vE)。

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 検索文字列に も追加しました。

編集2: OP を変更したようですね。上記の回答は元の質問に対するものです。以下に、役立つかもしれないスクリプトを作成しました: http://pastebin.com/uKWAGE0Y

関連情報