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.out
Daten 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 cat
ist 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, sed
um die maskierte Tilde in der 3. Spalte auszutauschen \~
. Anschließend können wir verwenden, cut
um 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, bc
der sie summiert.
Antwort3
Um mit dem Escapen umzugehen, besteht eine allgemeine Methode darin, perl
oder 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 sed
ist dies auch mit folgendem möglich:
sed -rn 's/((\\.|[^\~])*~){3}((\\.|[^~])*).*/\3/p'
Mit GNU awk
können Sie FPAT
Felder 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;
}'