Wie kann ich Escape-Trennzeichen in einem Unix-Befehl vermeiden?

Wie kann ich Escape-Trennzeichen in einem Unix-Befehl vermeiden?

Ich muss die Summe eines Felds berechnen, das durch Tilde (~) getrennt ist. Mein Problem besteht darin, dass in meinen Daten auch Trennzeichen maskiert sind.

Beispiel

1~CEO~ashok\~kumar~1000

Wie wir im 3. Feld oben sehen, haben wir ein Escape-Trennzeichen, das ich vermeiden möchte. Ich führe den folgenden Befehl aus, der dies nicht behandelt.

$ cat test.out|awk -F'~' 'BEGIN {sum=0} {sum+=$4} END{print sum}'

Nehmen Sie die test.outDaten wie folgt an:

1~CEO~ashok\~kumar~1000
2~CFO~Ranjan~2000
3~CEO~kumar~1000

Meine Ausgabe sollte also 4000 sein. Aber derzeit erhalte ich mit meinem Befehl nur 3000!

Antwort1

Ändern Sie einfach das Escape-Trennzeichen in etwas anderes, bevor Sie mit verarbeiten awk. Dies kann mit erfolgen sed:

$ cat test.out| sed 's/\\~/=/g' | \
    awk -F'~' 'BEGIN {sum=0} {sum+=$4} END{print sum}'
4000

Und wie so oft catist das nicht nötig:

$ sed 's/\\~/=/g' test.out | awk -F'~' 'BEGIN {sum=0} {sum+=$4} END{print sum}'

Antwort2

Hier ist eine Alternative, die nicht verwendet awk:

$ sed 's/\\~/=/g' test.out | cut -d"~" -f4 | paste -sd+ | bc
4000

Das Obige wird verwendet, sedum die maskierte Tilde in der 3. Spalte auszutauschen \~. Anschließend können wir verwenden, cutum die 4. Spalte mit Zahlen auszuwählen und sie dann so umzugestalten, dass sie durch Pluszeichen ( +) getrennt sind.

$ sed 's/\\~/=/g' test.out | cut -d"~" -f4 | paste -sd+
1000+2000+1000

Diese Zeichenfolge wird dann an den Binärrechner übergeben, bcder sie summiert.

Antwort3

Um mit dem Escapen umzugehen, besteht eine allgemeine Methode darin, perloder PCRE und ihren alternierenden Regexp-Operator in Kombination mit dem No-Backtrack-Operator zu verwenden. Hier mit GNU grep:

grep -Po '(?>(?:\\.|.)*?~){3}\K(?:\\.|[^~])*' << \EOF
1~CEO~ashok\~kumar~1000
2~CFO~Ranjan~2000
3~CEO~kumar~1000
4~field2~field3\\~10000~field5-note-the-escaped-backslash-not-tilde
5~a\~b\~c\~no-4th-field-here
EOF

Das Ergebnis ist:

1000
2000
1000
10000

(die Sie mit Ihren üblichen summieren können awk '{s+=$0};END{print s}').

Mit GNU sedist dies auch mit folgendem möglich:

sed -rn 's/((\\.|[^\~])*~){3}((\\.|[^~])*).*/\3/p'

Mit GNU awkkönnen Sie FPATFelder als Sequenzen aus Escape-Zeichen oder Zeichen, die weder Tilde noch Backslash sind, definieren:

awk -v FPAT='(\\\\.|[^\\\\~])*' '{print $4}'

Antwort4

Dies ist in awk etwas umständlich (es sei denn, Sie können Ihren Quelltext vorverarbeiten, um das Trennzeichen zu ändern, aber dazu müssen Sie ein anderes Zeichen oder eine andere Zeichenfolge kennen, die nicht in der Eingabe vorkommen kann). Sie können beispielsweise eine ganze Zeile lesen und dann die Zeile bearbeiten, um Zeilenumbrüche als Trennzeichen zu erhalten (Zeilenumbrüche sind das Einzige, was in einer Zeile unmöglich vorkommen kann).

awk 'BEGIN {FS="\n"}
{
    gsub("~", "\n");
    gsub("\\\n", "~");
    gsub("\\\\", "\\");
    $0 = $0;
    print $4;
}'

verwandte Informationen