Mehrfaches Abrufen von Teilzeichenfolgen zwischen Trennzeichen aus einer Zeichenfolge ohne Schleife

Mehrfaches Abrufen von Teilzeichenfolgen zwischen Trennzeichen aus einer Zeichenfolge ohne Schleife

Ich habe überall nach einer Lösung dafür gesucht, konnte aber keine finden.

Ich verwende , qstat -xum eine große Zeichenfolge mit Jobinformationen zu übergeben. Die Ausgabe von qstat -xerfolgt im XML-Format. Die gesuchten Teilzeichenfolgen befinden sich zwischen zwei expliziten Trennzeichen <Output_Path>und </Output_Path>. Hier ist ein Beispiel für einige der Ausgaben von qstat -x, wobei vertrauliche Informationen zensiert wurden:

<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>

Ich möchte alle Teilzeichenfolgen erhalten, die zwischen jeder Iteration von <Output_Path>und liegen </Output_Path>. Das heißt, wenn ich die Zeichenfolge

<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>

Ich möchte einen Befehl, der zurückgibt

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

oder

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

Aber ich muss es ohne langsame forSchleifen erledigen. Ich habe versucht, Variationen von awk, grep, und zu verwenden sed, konnte aber nichts finden, was funktioniert hat.

Irgendwelche Ideen?

Antwort1

Versuchen Sie dann Folgendes:

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

Antwort2

Wenn das Grep Ihres Systems PCRE unterstützt, könnten Sie vielleicht

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

oder wenn Sie allgemeinere Mengen umgebender Leerzeichen verarbeiten müssen

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

Antwort3

Wenn Sie mit etwas Strukturiertem wie diesem zufrieden sind:

string1
string2
string3

Ich würde einfach die Trennzeichen durch eine neue Zeile ersetzen. So etwas sollte Ihnen nahe kommen:

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

Bearbeiten

Wie @clk unten anmerkt, kann meine erste Antwort doppelte Zeilenumbrüche ergeben. Ändern Sie sie in etwas wie:

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

ergibt für mich:

 string1 string2 string3

was auch beim Einspeisen genauso funktioniert, wie beispielsweise:

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

Nicht sehrhübschAntwort, aber schnell und einfach und gibt Ihnen das Format, nach dem Sie fragen.

Antwort4

Nur sed verwenden (mit -rFlag für erweiterten regulären Ausdruck)

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

Kehrt zurück

string1 string2 string3 

Sie haben auch diese Version mit tr und grep (mit -vE):

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

Kehrt zurück

string1
string2
string3

trersetzt einfach das Leerzeichen durch ein neues Zeilenzeichen. grep -vEverwendet reguläre Ausdrücke („E“) und schließt die übereinstimmenden Zeilen („v“) aus.

Die dritte Version verwendet sed (ohne Flag) und grep (wie die letzte Version):

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

Macht so ziemlich genau dasselbe wie Version zwei, verwendet aber sed statt tr.

Bearbeiten: Außerdem wurde es ^$in der Grep-Suchzeichenfolge hinzugefügt, um sicherzustellen, dass keine unerwünschten Zeilenumbrüche zurückgegeben werden.

Edit2: Ich sehe, Sie haben das OP geändert. Die obige Antwort bezieht sich auf die ursprüngliche Frage. Unten habe ich ein Skript erstellt, das Ihnen vielleicht weiterhelfen könnte: http://pastebin.com/uKWAGE0Y

verwandte Informationen