Vielleicht so etwas wie:
sed 's/: /./;s/\(\([^.]*\.\)[^,]*\), /\1\
\2/;P;D'
Das sind zwei Zeilen ( \<LF>
können durch \n
einige sed
Implementierungen ersetzt werden).
Der D
Befehl ist eine Möglichkeit , zu implementieren , während Schleifen in sed
. Es entfernt die erste Zeile des Musterraums und solange noch etwas im Musterraum übrig ist, beginnt alles von vorne mit dem, was noch übrig ist. Das Obige kann also wie folgt gelesen werden:
do {
- change ": " to "." so we start with "23.a, b, c"
- change "23.x, y, z" to "23.x\n23.y, z"
- print the first line ("23.x"): P
- remove it
} while (pattern space is not empty)
Wir brauchen nicht den ersten s
Befehl, um Teil der Schleife zu sein, aber um dies zu vermeiden, müssten wir einen ausführlicheren Schleifentyp verwenden, wie die Verwendung von Beschriftungen ( :
) und Verzweigungsbefehlen ( b
, t
).
Egal, ich habe mich gerade an die awk split Funktion erinnert, was dies ziemlich einfach macht.
(Der gsub entfernt fremde Leerzeichen.)
Vielen Dank für die anderen Antworten.
quelle
FS
in solchen Fällen eine komplexere :awk -F '[:,]' '{for(i=2;i<=NF;i++)printf"%s%s\n",$1,$i}'
.awk
Implementierungen garantieren, dass Ihri in ps
Ausdruck zu einer Schleifenreihenfolge durch das Array führt. Zum Beispielmawk
, abergawk
nicht.awk
's Arrays sind assoziative Arrays und assoziative Arrays funktionieren normalerweise so (zum BeispielHashMap
in Java, Hash in Perl, diktieren in Python,Hash
in Ruby vor 1.9.2, Array in Tcl). Das liegt an der internen Darstellung der Daten. Software Engineering hat eine verwandte Frage: Ist ein assoziatives Array bestellt? ,Hier ist ein Perl:
ERLÄUTERUNG:
perl -nle
: Dies weist Perl an, die Eingabedatei zeilenweise zu analysieren (-n
), das als Argument angegebene Skript auszuführen-e
und\n
jeder gedruckten Zeichenfolge (-l
) eine neue Zeile ( ) hinzuzufügen ./(.+?):\s*(.+)/
: Ordnen Sie die ersten Zeichen bis zum ersten Doppelpunkt zu, gefolgt von 0 oder mehr Leerzeichen (:\s*
) und dem Rest der Zeile. Die Klammern sind Perl-Syntax zum Erfassen von Mustern, die beiden Übereinstimmungen werden als$1
und gespeichert$2
.split(/[,\s]*/,$2);
: Dies teilt$2
(das zweite übereinstimmende Muster aus der obigen Übereinstimmungsoperation) an,
und / oder Leerzeichen auf und erstellt ein anonymes Array.print "$1.$_" for split()
: Durchlaufen Sie das anonyme Array, das durch die obige Aufteilung erstellt wurde, speichern Sie jedes Array-Mitglied als$_
und drucken Sie es zusammen mit$1
(dem ersten im ersten Schritt erfassten Muster) und einem Punkt.
.quelle
print "$1.$_\n" for ..."
stattmap { print "$1.$_\n" } ...
.-l
dir nicht brauchen"\n"
. Könnte aber noch besser zu bedienen sein-E
undsay
.map
erstellt und gibt eine Liste von Werten zurück. Hier wird es alsfor
oder verwendetforeach
.say
das neu ist (perl> = 5.10 denke ich) und möglicherweise nicht immer verfügbar ist. Ich habe verwendet,map
weil dies ein Einzeiler ist und ich wollte es kürzer. Mir wurde klar, dass es in einer CompSci-Abteilung nicht für die Straße legal ist, aber es macht in diesem Zusammenhang wirklich keinen Unterschied.Hier ist ein Ruby:
Erläuterung
ruby -ane: Dies weist Ruby an,
a
die Zeilen einzeln zu teilenn
unde
das Argument als Skript auszuführen.In einer Auto-Split-Datei
$F
befindet sich ein Array des Split-Ergebnisses.drop(1)
Überspringt das erste Feld (die Zeilennummer) und.each
durchläuft die folgenden Felder.gsub
Ersetzt das:
undchomp
entfernt ein nachfolgendes Trennzeichen aus der Zeichenfolge.quelle
Ein awk-Einzeiler, den ich für etwas eleganter halte als die andere awk-Lösung:
Es nutzt die Tatsache aus, dass der awk-Feldtrenner ein regulärer Ausdruck ist.
quelle
Perl:
Teilt die Zeile in die erste Zahl und den Rest auf und druckt dann
"$first.$_"
für jeden der Buchstaben.quelle
Wie wäre es mit einem einfachen Bourne-Shell-Skript (meistens):
Der Befehl "tr" bereinigt nur die Doppelpunkte (:) und Kommas (,) - diese Antwort hängt davon ab, dass die Daten Leerzeichen enthalten (die in den Beispieldaten enthalten sind). Andernfalls müssen Sie sed verwenden, um: und stattdessen in Leerzeichen zu konvertieren von tr).
Die Ausgabe von "tr" wird in die äußere Schleife "beim Lesen ...; do ...; done" geleitet, die beim ersten Auftreten von Leerzeichen (oder besser gesagt beim Inhalt von "$ IFS" Zeilen liest und in zwei Teile zerlegt "- das Shell-Eingabefeldtrennzeichen (standardmäßig Leerzeichen), wobei das Präfix in" $ p "und der Rest der Zeile in" $ r "belassen wird.
Die innere Schleife "for i in ...; do ...; done" bricht dann den Inhalt von "$ r" im Leerzeichen ("$ IFS") auf und setzt jedes Element in "$ i", bevor der Echo-Befehl ausgeführt wird .
BEARBEITEN: siehe Kommentare - Sie brauchen überhaupt kein "tr" ... die Doppelpunkte und Kommas können bereinigt werden, indem Sie sie wie folgt in die IFS-Variable aufnehmen:
alles innerhalb der Shell erledigt - keine Aufrufe externer Programme ... (es sei denn, Echo ist nicht eingebaut). Beachten Sie, dass IFS = oben ein Leerzeichen und ein Tabulatorzeichen enthält. Beachten Sie auch, dass das $ r in der zweiten for-Schleife keine Anführungszeichen enthält - dies ist absichtlich so, dass die Shell es in Leerzeichen aufteilt.
quelle
tr ':,' ' ' | tr -s ' '
...OIFS="$IFS"; IFS=":, "; while read p r; do for i in $r; do echo "$p.$i"; done; done; IFS="$OIFS"
müssen die Shell niemals verlassen ... yay!