Ich habe eine Datei, die so aussieht und 2 Spalten hat (durch Leerzeichen getrennt):

chr1.21.imputed_info:1   100880328
chr1.31.imputed_info:1   10566215
chr1.23.imputed_info:--- 110198129
chr1.23.imputed_info:--- 114445880
chr1.24.imputed_info:--- 118141492
chr1.25.imputed_info:--- 120257110
chr1.25.imputed_info:1   121280613
chr1.30.imputed_info:--- 121287994
chr1.30.imputed_info:--- 145604302

Ich möchte die Zahl nach "chr" aus 1-22 und der zweiten Spalte extrahieren. Meine Ausgabe würde also so aussehen:

    1 100880328
    1 10566215
    1 110198129
    1 114445880
    1 118141492
    1 120257110
    1 121280613
    1 121287994
    1 145604302

Einige wichtige Überlegungen:

  • Wie gesagt, die Zahl direkt nach "chr" geht von 1-22, also könnte es chr1, chr2 ... chr22 sein.
  • Die Zahl nach chr1, chr2 usw. kann bis zu 50 betragen. Sie können also beispielsweise chr1.50 oder chr2.45 usw. Haben

  • Der Teil "info:" am Ende der Spalte1 sieht möglicherweise wie folgt aus: info: 1, info: 2 .. info: 22 ODER info: ---

Ich habe mir das in Bash ausgedacht:

cat file.txt | sed 's/chr//g' | sed 's/.imputed_info://g'

Das bringt mich sehr nahe, aber es macht das:

1.211    100880328
1.31     10566215
1.23---  110198129
1.23---  114445880
1.24---  118141492
1.25---  120257110
1.251    121280613
1.25---  121287994
1.30---  145604302
1.301    149906413

Ich weiß, dass es Möglichkeiten gibt, dies in R und Python zu tun, aber ich sollte sagen, dass dies eine riesige Datei ist, so dass das Durchlaufen von Bash eine große Zeitersparnis wäre. Wenn also jemand eine nette (und idealerweise saubere Lösung hat - ich erkenne meine Sed Befehl ist irgendwie hässlich) es wäre toll. Vielen Dank.

1
mf94 17 Apr. 2018 im 21:16

5 Antworten

Beste Antwort

Kürzere Art:

sed 's/^chr//;s/\..* / /' filename

BEARBEITEN:
Übersetzung: Entfernen Sie das führende "chr" (falls vorhanden) und ersetzen Sie alles vom ersten "." bis zum letzten Leerzeichen (dh einem '.', gefolgt von irgendetwas, gefolgt von '') mit einem einzelnen Leerzeichen.

5
Beta 17 Apr. 2018 im 19:45

Ich würde awk verwenden:

awk -F'[. ]' '{print substr($1,4), $NF}' file.txt

Dadurch wird jede Zeile nach Punkt oder Leerzeichen aufgeteilt und das erste Feld beginnend mit dem 4. Zeichen und dem letzten Feld gedruckt. (NF ist die Anzahl der Felder, $NF ist das letzte Feld)

Ausgabe:

1 100880328
1 10566215
1 110198129
1 114445880
1 118141492
1 120257110
1 121280613
1 121287994
1 145604302
3
hek2mgl 17 Apr. 2018 im 18:59

sed 's/chr\([0-9]*\)[^ ]*[ ]*\([0-9]*\)/\1\t\2/' file.txt

3
Krzysztof Kaszkowiak 17 Apr. 2018 im 19:45

Angenommen, Sie haben mit erweitertem Regex sediert:

sed -r -n 's/chr(2[0-2]|1?[0-9])\..+\s([0-9]+)/\1 \2/p' file.txt

Wenn die Zahl nach chr nicht höher als 22 sein darf, können Sie den Ausdruck auf vereinfachen (ohne erweiterten regulären Ausdruck)

sed -r 's/chr([0-9]+)\..+\s([0-9]+)/\1 \2/' file.txt

Regex erklärt

  • chr - Literal-Übereinstimmung
  • (2[0-2]|1?[0-9]) - erste übereinstimmende Gruppe
    • 2[0-2] - 20 bis 22
    • | oder (wenn es nicht 20-22 ist, testen Sie den nächsten Ausdruck in der Gruppe)
    • 1? - null oder eins 1
    • [0-9] - 0-9
  • \. - Literalpunkt
  • .+\s - ein oder mehrere Zeichen, gefolgt von einem Leerzeichen
  • ([0-9]+) - zweite übereinstimmende Gruppe, die mit einer oder mehreren Ziffern übereinstimmt

  • /\1 \2/ - durch erste und zweite übereinstimmende Gruppe ersetzen

Ergebnis

Ich habe Ihr Beispiel erweitert auf

chr1.21.imputed_info:1   100880328
chr2.31.imputed_info:1   10566215
chr11.23.imputed_info:--- 110198129
chr12.23.imputed_info:--- 114445880
chr22.24.imputed_info:--- 118141492
chr1.25.imputed_info:--- 120257110
chr1.25.imputed_info:1   121280613
chr1.30.imputed_info:--- 121287994
chr1.30.imputed_info:--- 145604302

Die Ausgabe von sed lautet:

1 100880328
2 10566215
11 110198129
12 114445880
22 118141492
1 120257110
1 121280613
1 121287994
1 145604302
1
rkta 17 Apr. 2018 im 19:40

Kurzer Weg:

sed 's/chr\([^.]*\).* /\1 /' file

Verwenden von sed unter allen angewendeten Bedingungen:

sed 's/^chr\(1[1-9]\{0,1\}\|10\|2[012]\)\.\(1[1-9]\{0,1\}\|10\|[234][0-9]\|50\)[^ ]*  *\([^ ]*\)/\1 \3/' file

Verwenden Sie sed nur mit der folgenden Syntax:

sed 's/^chr\([1-9][1-9]*\)\.[1-9][1-9]*[^ ]*  *\([^ ]*\)/\1 \2/' file

Verwenden von awk:

awk '
/^chr([0-9]+)\.[0-9]+/{
    match($1, /[0-9]+/);
    $1 = substr($1, RSTART, RLENGTH);
    print;
}' file

Ausgabe:

1 100880328
1 10566215
1 110198129
1 114445880
1 118141492
1 120257110
1 121280613
1 121287994
1 145604302
1
revo 17 Apr. 2018 im 20:12