Formatieren Sie die Ausgabe von xargs

10

Ich möchte das Format der Ausgabe-Xargs-Anzeigen ändern

cat k.txt 
1 
2 
3 

Und

cat k.txt | xargs 
1 2 3

Allerdings hätte ich gerne 1, 2, 3oder 1|2|3. Irgendwelche Vorschläge?

Avinash
quelle
Das könnte mit etwas (nicht genau dies) erreicht werden , wie xargs cat -n, aber es ist einfacher , wenn Sie nur die Zeilenumbrüche trimmen, kann dies erreicht werden durch echo $(cat), grepoder awk(Crawl die Art und Weise , es zu tun). xargspassen nicht gut für Ihren aktuellen Zweck.
41754

Antworten:

18

Im Folgenden finden Sie etwa ein Dutzend Beispiele dafür, wie Sie eine Datei wie diese erstellen können:

$ cat k.txt
1
2
3

und konvertieren Sie es in dieses Format:

1,2,3

Mit diesem Befehl können Sie die obige Datei erstellen, wenn Sie mitspielen möchten:

$ cat <<EOF > k.txt
1
2
3
EOF

Die folgenden Beispiele sind in zwei Gruppen unterteilt. Diejenigen, die "arbeiten" und diejenigen, die "fast" funktionieren. Ich lasse diese, weil es oft genauso wertvoll ist zu sehen, warum etwas nicht funktioniert, wie zu sehen, warum etwas funktioniert.

Die meisten mir bekannten Skriptsprachen sind vertreten. Einige sind mehrfach vertreten, da wie bei dem berühmten Akronym, auf das in Perl typischerweise Bezug genommen wird, TIMTOWTDI .

HINWEIS: Sie können das Komma ( ,) in den folgenden Beispielen austauschen und durch beliebige Zeichen ersetzen, z |.

Beispiele, die "funktionieren"

Diese Codefragmente erzeugen die gewünschte Ausgabe.

Der pasteBefehl:

$ paste -s -d ',' k.txt 
1,2,3

Der sedBefehl:

$ sed ':a;N;$!ba;s/\n/,/g' k.txt
1,2,3

$ sed ':a;{N;s/\n/,/};ba' k.txt 
1,2,3

Der perlBefehl:

$ perl -00 -p -e 's/\n(?!$)/,/g' k.txt
1,2,3

$ perl -00 -p -e 'chomp;tr/\n/,/' k.txt
1,2,3

Der awkBefehl:

$ awk '{printf"%s%s",c,$0;c=","}' k.txt
1,2,3

$ awk '{printf "%s,",$0}' k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

$ awk -vORS=, 1 k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

$ awk 'BEGIN {RS="dn"}{gsub("\n",",");print $0}' k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

Der pythonBefehl:

$ python -c "import sys; print sys.stdin.read().replace('\n', ',')[0:-1]" <k.txt
1,2,3

$ python -c "import sys; print sys.stdin.read().replace('\n', ',').rstrip(',')" <k.txt
1,2,3

Bash ist mapfileeingebaut:

$ mapfile -t a < k.txt; (IFS=','; echo "${a[*]}")
1,2,3

Der rubyBefehl:

$ ruby -00 -pe 'gsub /\n/,",";chop' < k.txt
1,2,3

$ ruby -00 -pe '$_.chomp!"\n";$_.tr!"\n",","' k.txt
1,2,3

Der phpBefehl:

$ php -r 'echo strtr(chop(file_get_contents($argv[1])),"\n",",");' k.txt
1,2,3

Vorsichtsmaßnahmen

Die meisten der obigen Beispiele funktionieren einwandfrei. Einige haben versteckte Probleme, wie das obige PHP-Beispiel. Die Funktion chop()ist eigentlich ein Alias ​​für rtrim(), sodass auch die nachgestellten Leerzeichen der letzten Zeile entfernt werden.

Dies gilt auch für das erste Ruby-Beispiel und das erste Python-Beispiel. Das Problem ist, wie sie alle eine Art von Operation verwenden, die im Wesentlichen blind einen nachgestellten Charakter "abschneidet". Dies ist in Ordnung für das Beispiel, das das OP bereitgestellt hat, aber bei der Verwendung dieser Typen von Einzeilern muss vorsichtig vorgegangen werden, um sicherzustellen, dass sie mit den Daten übereinstimmen, die sie verarbeiten.

Beispiel

Sagen Sie unsere Beispieldatei, k.txtsah stattdessen so aus:

$ echo -en "1\n2\n3" > k.txt

Es sieht ähnlich aus, hat aber einen kleinen Unterschied. Es hat keine abschließende Newline ( \n) wie die Originaldatei. Wenn wir nun das erste Python-Beispiel ausführen, erhalten wir Folgendes:

$ python -c "import sys; print sys.stdin.read().replace('\n', ',')[0:-1]" <k.txt
1,2,

Beispiele, die "fast" funktionieren

Dies sind die Beispiele "immer eine Brautjungfer, nie eine Braut" . Die meisten von ihnen könnten wahrscheinlich angepasst werden, aber wenn man an einer möglichen Lösung für ein Problem arbeitet und sich "gezwungen" fühlt, ist es wahrscheinlich das falsche Werkzeug für den Job!

Der perlBefehl:

$ perl -p -e 's/\n/,/' k.txt
1,2,3,

Der trBefehl:

$ tr '\n' ','  < k.txt 
1,2,3,

Die cat+ echoBefehle:

$ echo $(cat k.txt)
1 2 3

Der rubyBefehl:

$ ruby -pe '$_["\n"]=","' k.txt
1,2,3,

Bash's while+ readeingebaute:

$ while read line; do echo -n "$line,"; done < k.txt
1,2,3,
slm
quelle
1
In Bezug auf awkich bevorzuge eine kürzere Alternative:awk -vORS=, 1 k.txt
Manatwork
Nicht sicher, ob CentOS hat bash:mapfile -t a < k.txt; (IFS=','; echo "${a[*]}")
Manatwork
Ich bin mir nicht sicher über die nachfolgende Newline. Nach meinem Test hat dein perlund zuerst awksie auch.
Manatwork
Ich würde pasteden oben platzieren. Genau dafür paste -sist es hier. Es ist ein Standardbefehl und wäre der effizienteste. Alle anderen sind übertrieben und / oder nicht tragbar oder haben Einschränkungen.
Stéphane Chazelas
mapfileist relativ neu, hinzugefügt in bash4.0.
Manatwork
4

@slm hat schon eine nette Antwort gegeben, aber als deine Frage "Formatausgabe von xargs"

xargs -I{} echo -n "{}|" < test.txt
  • -I ist die Option "Zeichenfolgen ersetzen".
  • {} ist ein Platzhalter für den Ausgabetext.
  • Dies ähnelt der Verwendung eines geschweiften Klammerpaars in "find".

Wenn Sie das Nachlaufen loswerden möchten, |können sedSie einige Aufräumarbeiten durchführen:

$ xargs -I{} echo -n "{}|" < k.txt  | sed -e 's/|$//'
1|2|3
Rahul Patil
quelle
Damit wird nach dem 3. "1 | 2 | 3 |" ein zusätzliches Rohr angeheftet. Ich habe das gleiche Problem mit einer while-Schleife und einer awk-Lösung.
slm
ja, wenn es neue Linie .. tr, sedund andere auch ..
Rahul Patil
2

Das ist ein alter Thread, ich weiß. Das OP fragte mit einem einfachen Code wie diesem. Um es nahe am Original zu halten, habe ich eine einfache Lösung.

cat k.txt | xargs
1 2 3

benutze sed

cat k.txt | xargs | sed 's/ /,/g'
1,2,3

oder

cat k.txt | xargs | sed 's/ /|/g'
1|2|3

sed kann etwas seltsam aussehen, ist aber kaputt, es macht viel Sinn.

ist für Ersatz. g 'ist für global: ohne dies wird nur die erste Ersetzung in jeder neuen Zeile durchgeführt. Da Sie 'xargs' verwenden, werden diese als eine Zeile angezeigt. Sie erhalten also "1,2 3".

Das Trennzeichen wird zur Trennung verwendet. Ich habe das Zeichen / verwendet. Ein interessanter Trick: Sie können das Trennzeichen durch fast jedes andere Zeichen ersetzen, solange wir zwischen den Anführungszeichen das gleiche Format beibehalten. Das würde also auch funktionieren ....

cat k.txt | xargs | sed 's# #,#g'

oder

cat k.txt | xargs | sed 'sT T,Tg'

Die Verwendung bestimmter Zeichen als Trennzeichen kann natürlich verwirrend sein. Seien Sie also schlau.

Michael Bruce
quelle
0
xargs <k.txt | tr \  \|

Sie brauchen nicht cat- übergeben Sie einfach die Dateieingabe und - wenn kein anderer Befehl gegeben wird - xargsgeben Sie das Standardformat aus - das von einer Art mit /bin/echo's ist (ohne Backslash-C-Escape-Interpretationen) .

xargsentfernt Kopf- / Schwanz-Leerzeichen aus der Eingabedatei und drückt andere Leerzeichenfolgen auf ein einzelnes Leerzeichen. Dies bedeutet, dass beim Übergeben der Datei von trzu xargsmögen:

tr \\n \| <k.txt | xargs

... druckt ...

1|2|3|

... in die andere Richtung gehen und nur mit den Argumenten arbeiten , die durch xargsLeerzeichen begrenzt werden ....

1|2|3\n

... weil xargsdie letzte nachfolgende neue Zeile gedruckt wird (wie für eine Textdatei erforderlich) , diese aber nicht auf trdiese Weise übersetzt wird.

Beachten Sie jedoch, dass diese (oder jede andere hier angebotene Lösung) das xargsZitieren in der Eingabe nicht berücksichtigt . xargswird buchstäblich Single / Double / Backslash-zitierte Nicht-Newline-Whitespace-Zeichen in der Eingabe ausgeben, die selbst wie folgt zitiert werden können:

xargs <<\IN
1    2'      3'\'      \'4
IN

1 2      3' '4
mikeserv
quelle