it-swarm.com.de

Prägnante und tragbare "Verknüpfung" auf der Unix-Befehlszeile

Wie kann ich mehrere Zeilen zu einer Zeile zusammenfügen, mit einem Trennzeichen, in dem sich die Zeilen der neuen Zeile befanden, und ein nachfolgendes Trennzeichen vermeiden und leere Zeilen optional ignorieren?

Beispiel. Betrachten Sie eine Textdatei foo.txt mit drei Zeilen:

foo
bar
baz

Die gewünschte Ausgabe ist:

foo,bar,baz

Der Befehl, den ich jetzt verwende:

tr '\n' ',' <foo.txt |sed 's/,$//g'

Im Idealfall würde es so aussehen:

cat foo.txt |join ,

Was ist:

  1. der tragbarste, prägnanteste und lesbarste Weg.
  2. der prägnanteste Weg mit nicht standardmäßigen Unix-Tools.

Natürlich könnte ich etwas schreiben oder einfach einen Alias ​​verwenden. Ich bin aber an den Möglichkeiten interessiert.

69
butt

Ein wenig überraschend ist paste ein guter Weg, dies zu tun:

paste -s -d","

Dies behandelt nicht die leeren Zeilen, die Sie erwähnt haben. Pipe deinen Text zuerst durch grep, zuerst:

grep -v '^$' | paste -s -d"," -
112

Diese sed-Zeile sollte funktionieren -

sed -e :a -e 'N;s/\n/,/;ba' file

Prüfung:

[jaypal:~/Temp] cat file
foo
bar
baz

[jaypal:~/Temp] sed -e :a -e 'N;s/\n/,/;ba' file
foo,bar,baz

Um leere Zeilen zu bearbeiten, können Sie die leeren Zeilen entfernen und an den obigen Einzeiler weiterleiten. 

sed -e '/^$/d' file | sed -e :a -e 'N;s/\n/,/;ba'
12
jaypal singh

Wie wäre es mit xargs?

für deinen Fall

$ cat foo.txt | sed 's/$/, /' | xargs

Achten Sie auf die maximale Länge der Eingabe des Befehls xargs. (Dies bedeutet, dass sehr lange Eingabedateien nicht behandelt werden können.)

8
plhn

Perl:

cat data.txt | Perl -pe 'if(!eof){chomp;$_.=","}'

oder noch kürzer und schneller, überraschenderweise:

cat data.txt | Perl -pe 'if(!eof){s/\n/,/}'

oder wenn du willst:

cat data.txt | Perl -pe 's/\n/,/ unless eof'
6
mykhal

Nur zum Spaß ist hier eine Komplettlösung

IFS=$'\n' read -r -d '' -a data < foo.txt ; ( IFS=, ; echo "${data[*]}" ; )

Sie können printf anstelle von echo verwenden, wenn der nachfolgende Zeilenumbruch ein Problem ist.

Dies funktioniert durch Einstellen von IFS, den Begrenzungszeichen, an denen read aufgeteilt wird, auf Newline und nicht auf andere Leerzeichen. Dann wird read angewiesen, das Lesen nicht zu stoppen, bis es eine nul erreicht, anstelle der Newline, die es normalerweise verwendet, und um jedes gelesene Element hinzuzufügen die Daten des Arrays (-a). Dann setzen wir in einer Subshell, um die IFS der interaktiven Shell nicht zu blockieren, IFS auf , und erweitern das Array mit *, wodurch jedes Element im Array mit dem ersten Zeichen in IFS begrenzt wird.

4
Sorpigal

Einfache Möglichkeit, die Zeilen mit Leerzeichen mit ex zu verbinden (leere Zeilen ignorieren), verwenden Sie:

ex +%j -cwq foo.txt

Wenn Sie die Ergebnisse in der Standardausgabe drucken möchten, versuchen Sie Folgendes:

ex +%j +%p -scq! foo.txt

Um Zeilen ohne Leerzeichen zu verbinden, verwenden Sie +%j! anstelle von +%j.

Um andere Begrenzer zu verwenden, ist es etwas schwieriger:

ex +"g/^$/d" +"%s/\n/_/e" +%p -scq! foo.txt

wobei g/^$/d (oder v/\S/d) leere Zeilen entfernt und s/\n/_/ eine Ersetzung ist, die im Grunde genauso funktioniert wie sed, jedoch für alle Zeilen (%). Wenn die Analyse abgeschlossen ist, drucken Sie den Puffer (%p). Und schließlich -cq!, das den vi q!-Befehl ausführt, der grundsätzlich ohne Speichern beendet wird (-s dient zum Stummschalten der Ausgabe).

Bitte beachten Sie, dass ex äquivalent zu vi -e ist.

Diese Methode ist ziemlich portabel, da die meisten Linux/Unix standardmäßig mit ex/vi ausgeliefert werden. Und es ist kompatibler als die Verwendung von sed, wobei der In-Place-Parameter (-i) keine Standarderweiterung ist und das Dienstprogramm it-self eher stromorientiert ist.

0
kenorb

Ich hatte eine Protokolldatei, in der einige Daten in mehrere Zeilen aufgeteilt waren. In diesem Fall war das letzte Zeichen der ersten Zeile das Semikolon (;). Ich habe diese Zeilen mit den folgenden Befehlen verbunden:

for LINE in 'cat $FILE | tr -s " " "|"'
do
    if [ $(echo $LINE | egrep ";$") ]
    then
        echo "$LINE\c" | tr -s "|" " " >> $MYFILE
    else
        echo "$LINE" | tr -s "|" " " >> $MYFILE
    fi
done

Das Ergebnis ist eine Datei, in der Zeilen, die in der Protokolldatei aufgeteilt wurden, eine Zeile in der neuen Datei waren.

0
Mark Dyer

Ich musste etwas Ähnliches erledigen, indem ich eine durch Kommas getrennte Liste von Feldern aus einer Datei druckte, und war zufrieden damit, STDOUT an xargs und Ruby zu leiten, wie folgt:

cat data.txt | cut -f 16 -d ' ' | grep -o "\d\+" | xargs Ruby -e "puts ARGV.join(', ')"
0
mchail