Erklärung eines sed-Befehls

Erklärung eines sed-Befehls

Ich habe diesen interessanten Befehl gefunden:

grep -v '^>' test.fasta | tr -d '\n' | sed -e 's/\(.\)/\1\n/g' | sort | uniq -c | sort -rn

Ich verstehe ungefähr, was es bedeutet (es zählt Buchstaben aus einer Textdatei), aber meine Frage betrifft Folgendes:

sed -e 's/\(.\)/\1\n/g'

Ich weiß, dass es aus drei Ersetzungsbefehlen besteht. Einer ersetzt neue Zeilen ( \n), einer passt zu allen Zeichen außer Zeilenumbrüchen ( \(.\)), aber ich bin ratlos /\1\.

Antwort1

Der Befehl

sed -e 's/\(.\)/\1\n/g'

ist ein einzelner GNU- sedErsetzungsbefehl, der jedes Zeichen durch sich selbst ersetzt, gefolgt von einem Zeilenumbruchzeichen. Dies bewirkt, dass die Eingabe in eine einzelne Spalte mit einzelnen Zeichen zusammengefasst wird.

$ echo hello | sed -e 's/\(.\)/\1\n/g'
h
e
l
l
o

Dies \(.\)ist eine „Erfassungsgruppe“, die ein einzelnes Zeichen erfasst. Dies \1ist ein „Rückverweis“ auf die erste Erfassungsgruppe. Die Verwendung \1im Ersetzungstext würde alles einfügen, was von der ersten Klammer erfasst wurde.

Es könnte auch ohne so viele Backslashes geschrieben werden wie

sed 's/./&\n/g'

wobei „wobei &“ einfach „alles, was mit dem Ausdruck übereinstimmt“ bedeutet.

Der sedBefehl erfordert GNU, sedda dieser Standard sedkeine Zeilenumbrüche einfügen kann \n.

Um dies mit Standardwerkzeugen effizienter zu erledigen, verwenden Sie

fold -w 1

stattdessen. Dies ist effizienter, da kein regulärer Ausdrucksabgleich für jedes Zeichen in der Eingabe erforderlich ist.

Mit foldkönnte Ihre Pipeline wie folgt geschrieben werden:

grep -v '^>' file | tr -d '\n' | fold -w 1 | sort | uniq -c | sort -rn

Alternativ können Sie awkeinige Schritte dieser Pipeline eliminieren,

awk '!/^>/ { for (i = 1; i <= length; ++i) count[substr($0,i,1)]++ }
    END { for (ch in count) print count[ch], ch }' file |
sort -rn

Der awkCode zählt, wie oft jedes Zeichen gesehen wurde. Dies geschieht, indem der Wert im Array erhöht wird, countder jedem Zeichen im Eingabestrom entspricht. Am Ende der Eingabe wird eine Zusammenfassung der Zählungen und gezählten Zeichen ausgegeben.

Antwort2

Ich hoffe, das macht es klarer.

„Ich weiß, dass es sich um drei Ersatzbefehle handelt“

Es handelt sich lediglich um einen Ersatzbefehl (falls Sie den Befehl meinen sed): s/<pattern to search>/<replacement>/, der Folgendes ausführt:

  • Suchen Sie für jede Zeile nach <pattern>und ersetzen Sie sie durch <replacement>.
  • Die gFlagge bedeutetTu esGglobal, da standardmäßig sednur das erste Vorkommen von ersetzt wird <pattern>.

"aber ich bin verloren bei /\1\"

Sie können ein Muster erfassen, indem Sie es mit Escape-Klammern \(<pattern>\)oder nur Klammern mit der -EOption umgeben (<pattern>).

Im <replacement>Abschnitt wird dieses erfasste Muster durch einen Backslash und eine Nummer referenziert \<number>. Die Nummer bezieht sich auf die Position der Erfassung, da es mehrere geben kann:

sed -E '/(<first capture>)(<second capture>)/\1\2/'

Der Befehl sed -e 's/\(.\)/\1\n/g'bedeutet also:

  • Erfassen Sie jedes Zeichen \(.\)und ersetzen Sie es durch sich selbst und eine neue Zeile \1\n.
  • Machen Sie es mit gglobal und hören Sie nicht beim ersten Vorkommen auf.

Zum Beispiel:

$ echo foo | sed -E 's/(.)/\1\n/g'
f
o
o


Die -eOptionen sind hier nicht erforderlich, es sei denn, Sie verketten mehrere sedBefehle: sed -e '...' -e '...'usw.


Weitere Informationen finden Sie unterRückverweise und Unterausdrücke.

Antwort3

Verwenden von Raku (früher bekannt als Perl_6)

raku -e 'for lines.grep({ !/ ^ \> / }).join { .say for .comb.Bag.sort(*.values).reverse};'

Beispieleingabe:

>sp|P01308|INS_HUMAN Insulin OS=Homo sapiens OX=9606 GN=INS PE=1 SV=1
MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAED
LQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN

Beispielausgabe:

L => 20
G => 12
A => 10
E => 8
Q => 7
P => 6
C => 6
V => 6
R => 5
S => 5
Y => 4
F => 3
T => 3
N => 3
M => 2
D => 2
K => 2
I => 2
W => 2
H => 2

Der von Ihnen präsentierte Code kann in einer Reihe von Sprachen (nicht nur sed) geschrieben sein, von denen jede Ihnen gefallen könnte. Ihr Code oben wurde beispielsweise in Raku, einem Mitglied der Perl-Sprachfamilie, neu geschrieben.

Der Großteil des Raku-Codes sollte ziemlich selbsterklärend sein: lineswerden eingelesen und grepmit -ped versehen, wenn am Zeilenanfang kein „Größer-als“-Winkel !vorhanden ist , und mit -ed versehen. Verbundene Zeilen werden mit -ed (in einzelne Zeichen aufgeteilt), -ged (jedes vorhandene Zeichen wird zu einem und Vorkommen werden als gezählt/aufgezeichnet ), -ed , um die höchste Anzahl von Vorkommen zuerst zu platzieren, und dann mit gedruckt .^>joincombBagkeyvaluessortreversesay

https://raku.org

verwandte Informationen