2016-07-04 7 views
0

In der Datei Datei unter:schneiden das erste Feld in einem mehrere Felder

position1 456754 0/1:170,167:339:99:3370,0,3372:50:99:0.496 ./.:.:.:.:.:.:.:. 
position2 456759 0/1:161,162:325:99:3266,0,3215:50:99:0.502 ./.:.:.:.:.:.:.:. 

Ich möchte die Ausgabe erhalten:

position1 456754 0/1 ./. 
position2 456759 0/1 ./. 

, die für die dritte und vierte Feld ist, möchte ich erhalten die ersten Felder /

enthält Wenn es nur eine Spalte ist, kann ich folgendes tun:

cut -d " " -f3 - | cut -f1 -d ":" 

Nach den ersten beiden Spalt einfügen, das würde mir nur geben:

position1 456754 0/1 
position2 456759 0/1 

Meine Datei um 200 Spalten hat, wie kann ich dies in der Datei für alle Felder erweitern?

Antwort

1

Sie könnten einen awk-Einstrich erstellen, der Felder mit Doppelpunkten aufteilt und diese durch Leerzeichen begrenzten Felder durch nur ein Unterfeld ersetzt. Etwas wie folgt aus:

$ cat inp.txt 
position1 456754 0/1:170,167:339:99:3370,0,3372:50:99:0.496 ./.:.:.:.:.:.:.:. 
position2 456759 0/1:161,162:325:99:3266,0,3215:50:99:0.502 ./.:.:.:.:.:.:.:. 
$ awk '{ for(i=1; i<=NF; i++) { if($i~/:/){split($i,a,":"); $i=a[1] } } } 1' inp.txt 
position1 456754 0/1 ./. 
position2 456759 0/1 ./. 

Die for Schleife geht durch die Liste der Felder. Wenn ein Feld einen Doppelpunkt enthält, geben wir das Feld split() in ein Array ein (a) und ersetzen das gesamte Feld ($i) durch nur das erste Element (a[1]). Die 1 am Ende der Befehlszeichenfolge ist Abkürzung für "diese Zeile drucken", die unabhängig davon erfolgt, ob Ersetzungen vorgenommen wurden.

Wenn Sie einen einfacheren awk-Skript auf Kosten einige CPU wollen, soll dies auch funktionieren:

$ awk '{ for(i=1; i<=NF; i++) { split($i,a,":"); $i=a[1] } } 1' inp.txt 

Dies beseitigt einfach, dass if() Zustand, so dass in jeder Zeile für jedes Feld, ersetzen Sie, dass Feld mit dem "ersten Doppelpunkt-Unterfeld". Bei Feldern ohne Doppelpunkt ersetzt dies das Feld mit sich selbst.

Alternativ für eine weniger robuste Lösung, könnten Sie sed verwenden:

$ sed -r -e 's/(:[^ ]*)(|$)/\2/g' inp.txt 
position1 456754 0/1 ./. 
position2 456759 0/1 ./. 

Diese Lösung liest und Ersatzketten innerhalb der Linie, anstatt Felder, um die Art und Weise Parsen awk Dinge tat. Es wäre wahrscheinlich genau so zuverlässig wie eine awk-Lösung, wenn auch vielleicht etwas weniger flexibel (zum Beispiel würde awk ein anderes Unterfeld zulassen, während dies bei sed nicht der Fall wäre).

Beachten Sie die g am Ende des Ersetzungsbefehls. Das sagt sed, diese Ersetzung "global" auszuführen und nicht nur bei der ersten Übereinstimmung der Suchregex.

Diese Lösung verwendet die Option -r, um sed zu veranlassen, erweiterte reguläre Ausdrücke zu verwenden. Wenn Sie OS X oder einige (ältere) Varianten von BSD-Unix verwenden, verwenden Sie stattdessen die Option -E. In anderen Ländern müssen Sie dies möglicherweise in BRE konvertieren.

Nur zwei Methoden. Ich bin mir sicher, dass mehr in anderen Antworten auftauchen wird.

Verwandte Themen