So ersetzen Sie Text in einer Spalte

7

Ich habe eine riesige Datei (mehr als 2 GB), in der die Daten wie folgt sind.

12,324,32342,E:fsdsf,23432,34534,45345,324

13,3224,342,E:werwefsdsf,23432,34534,45345,324

121,3244,33442,E:,23432,34534,45345,324

Hier muss ich alle Vorkommen der 4. Spalte ersetzen, wo immer sie auf E:ein Leerzeichen stößt "", aber wo immer sie danach eine Zeichenfolge E:findet, sollte diese so bleiben, wie sie ist.

Die erwartete Ausgabe wäre:

12,324,32342,E:fsdsf,23432,34534,45345,324

13,3224,342,E:werwefsdsf,23432,34534,45345,324

121,3244,33442,,23432,34534,45345,324
Anurag
quelle
Ich habe Folgendes versucht - awk -F, '{if ($ 4 = "E:") $ 4 = "";} 1' OFS =, data.final, aber dies ersetzt alle Vorkommen von $ 4 durch ein Leerzeichen.
Anurag

Antworten:

8

Ihre Syntax ist fast richtig. awkVerwenden Sie zum Testen der Zeichenfolgengleichheit ein doppeltes Gleichheitszeichen : ==. Verwenden Sie zum Zuweisen eines Werts ein einzelnes Gleichheitszeichen.

Verwenden if ($4 == "E:")Sie also und Sie sollten das gewünschte Ergebnis erhalten.

Der vollständige Befehl würde so aussehen. Beachten Sie, dass es nur einen Zeichenunterschied zu dem von Ihnen verwendeten Befehl gibt. das war dein einziger Fehler:

awk -F , '{ if ($4 == "E:") $4="";}1' OFS=, data.final

Um einige unterschiedliche Syntax und Ansätze zu zeigen, sind die folgenden Versionen genau gleichwertig:

awk -F, -v OFS=, '$4 == "E:" { $4 = "" }; 1' data.final

awk 'BEGIN { FS=OFS="," }; $4 == "E:" { $4 = "" }; {print}' data.final

awk -F, -v OFS=, '{sub( /^E:$/, "", $4); print}' data.final

Anmerkungen zu den oben genannten Punkten:

  1. Wenn Ihr gesamter Codeblock nur ein Wenn / Dann ist, können Sie die Bedingung einfach als Filter für den Codeblock verwenden. Daher $4 == "E:" {$4 = ""}ist genau gleichbedeutend mit{if ($4 == "E:") {$4 = ""}}
  2. Es ist empfehlenswert, "then" -Anweisungen in einen Codeblock einzuschließen, selbst wenn nur eine davon vorhanden ist, dh if ($4 == "E:") {$4 = ""}nichtif ($4 == "E:") $4 = "";
  3. -FLegt den Wert von fest FSund -vkann verwendet werden, um den Wert einer Variablen festzulegen, bevor awkdie erste Zeile der ersten Datei berücksichtigt wird. (Das wussten Sie wahrscheinlich.) Sie können auch einen BEGINBlock verwenden, um dasselbe zu tun. Es lohnt sich zu wissen, wann Sie das awkSkript eigenständig machen möchten .
  4. Der Grund, warum 1Zeilen gedruckt werden, awkbesteht darin, dass es sich um eine Bedingung (einen Filter) handelt, die immer als wahr ausgewertet wird, und die Standardaktion, awkwenn kein Codeblock an den Filter angehängt ist, lautet print $0. Also 1an sich ist gleichbedeutend mit 1 {print}oder 1 {print $0}oder nur {print}.
  5. In meiner letzten Variante habe ich eine subFunktion verwendet, um den regulären Ausdruck /^E:$/(Anfang der Zeichenfolge E:, Ende der Zeichenfolge) durch ""in zu ersetzen $4.

Da die subFunktion die Anzahl der vorgenommenen Ersetzungen zurückgibt (entweder 1 oder 0; verwenden Sie gsub, um mehr als eine Ersetzung vorzunehmen), können Sie dieses Problem codieren, indem Sie dem subFunktionsergebnis eine hinzufügen, um sicherzustellen, dass Sie ein Muster haben, das immer wahr ist dass die resultierende Zeile gedruckt wird, unabhängig davon, ob eine Ersetzung vorgenommen wurde oder nicht. Hier ist die Code-Golf-Version, die für Anfänger nicht empfohlen wird, wenn Sie diese in ein Skript einfügen, das Sie dann pflegen:

awk -F, -v OFS=, 'sub(/^E:$/,"",$4)+1' data.final

:) :)

Platzhalter
quelle
2

Mit sed:

sed -r 's/^([^,]+,[^,]+,[^ ]+,)E:(,)/\1\2/' file.txt

Das durch Kommas getrennte 4. Feld wird leer gelassen, wenn es nur enthält E:.

Beispiel:

% cat file.txt
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,E:,23432,34534,45345,324

% sed -r 's/^([^,]+,[^,]+,[^ ]+,)E:(,)/\1\2/' file.txt 
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,,23432,34534,45345,324
heemayl
quelle
s tream ed itor +1
Pandya
0

Angenommen, Ihr Dateiname lautet file, können Sie Folgendes versuchen:

while read -r line; 
do 
var="$(echo "$line" | cut -d ',' -f 4)";

  if [[ "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/''/g ; 
  else echo "$line";
  fi; 

done < file

oder:

while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/''/g ; else echo "$line";fi; done < file

Erläuterung:

  1. while read -r line; liest die Datei Zeile für Zeile
  2. var="$(echo "$line" | cut -d ',' -f 4)";Wunden die Zeichenfolge an 4. Stelle durch ,Variable getrenntvar
  3. if [[ && "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/' '/g ;Wenn $vargenau eine Zeichenfolge vorhanden ist, E:wird sed s/"$var"/''/g ;diese durch eine leere Zeichenfolge ersetzt""
  4. else echo "$line"; Andernfalls wird die Linie so gedruckt, wie sie ist

Beispiel Ausgabe (ab Frage erwartet):

  • file::

    $ cat file
    12,324,32342,E:fsdsf,23432,34534,45345,324
    
    13,3224,342,E:werwefsdsf,23432,34534,45345,324
    
    121,3244,33442,E:,23432,34534,45345,324
    
  • Ausführender Befehl:

    $ while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" |sed s/"$var"/' '/g ; else echo "$line";fi; done < file
    12,324,32342,E:fsdsf,23432,34534,45345,324
    
    13,3224,342,E:werwefsdsf,23432,34534,45345,324
    
    121,3244,33442,,23432,34534,45345,324
    

Sie können Ihre Ausgabe auch mit >> file2oder |tee file2am letzten Befehl in eine Datei umleiten :

while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" |sed s/"$var"/' '/g ; else echo "$line";fi; done < file | tee file2
Pandya
quelle