Mehrzeilige Zeichenfolge in durch Kommas getrennte Zeichenfolge umwandeln


95

Angenommen, ich habe die folgende Zeichenfolge:

something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)

Wie mache ich das einfach?

+12.0,+15.5,+9.0,+13.5

in Bash?


Lassen Sie uns einen Moment zurücktreten und diesen Thread als eklatante Anklage gegen Bash als Programmiersprache betrachten. Betrachten Sie Scala listOfStuff mkString ", "oder Haskellintercalate ", " listOfString
FP Freely

Antworten:


92

Sie können verwenden awkund sed:

awk -vORS=, '{ print $2 }' file.txt | sed 's/,$/\n/'

Oder wenn Sie eine Pfeife verwenden möchten:

echo "data" | awk -vORS=, '{ print $2 }' | sed 's/,$/\n/'

Um es aufzuschlüsseln:

  • awk eignet sich hervorragend für den Umgang mit Daten, die in Felder unterteilt sind
  • -vORS=,setzt das "Ausgabedatensatztrennzeichen" auf ,das, was Sie wollten
  • { print $2 }weist awkan, das zweite Feld für jeden Datensatz (Zeile) zu drucken
  • file.txt ist Ihr Dateiname
  • sed,Entfernt einfach das Trailing und verwandelt es in eine neue Zeile (wenn Sie keine neue Zeile möchten, können Sie dies tun s/,$//)

1
awk: ungültig -v Option :(
Marsellus Wallace

6
Fügen Sie ein Leerzeichen zwischen -v und ORS = hinzu (für mich auf osx)
Graham P Heath

Wie mache ich den gleichen Befehl, um das Rohr zu trennen? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'
Ich

2
Seltsamerweise ist die Ausgabe leer, wenn ich dies versuche.
eternaltyro

1
Ich denke, für die Piped-Version sollte es so sein, {print $1}sonst bekomme ich nur Kommas in der Ausgabe
Przemysław Czechowski

162

Sauber und einfach:

awk '{print $2}' file.txt | paste -s -d, -

3
Dies ist die beste Antwort hier und offensichtlich der richtige Weg, dies zu tun
forresthopkinsa

Wie zitiere ich alle Werte mit einfachem / doppeltem Anführungszeichen?
Hussain

1
@ Hussaincat thing | awk -F',' '{ print "'\''" $7 "'\' '" }' | paste -s -d ','
Starbeamrainbowlabs

Wie ,'als Trennzeichen verwenden?
Kasun Siyambalapitiya

Denken Sie daran, Windows-Zeilenumbrüche (z. B. using dos2unix) zu behandeln, wenn die Zeichenfolge CRLFs enthält.
Bowi


10
$ awk -v ORS=, '{print $2}' data.txt | sed 's/,$//'
+12.0,+15.5,+9.0,+13.5

$ cat data.txt | tr -s ' ' | cut -d ' ' -f 2 | tr '\n' ',' | sed 's/,$//'
+12.0,+15.5,+9.0,+13.5

Prost, was ist, wenn die Eingabe für awk über die Standardeingabe erfolgte (nur function | awk...in Ihrem Beispiel?
Alex Coplan

10

awk ein Liner

$ awk '{printf (NR>1?",":"") $2}' file

+12.0,+15.5,+9.0,+13.5

8

Das sollte auch funktionieren

awk '{print $2}' file | sed ':a;{N;s/\n/,/};ba'

8

Dies könnte für Sie funktionieren:

cut -d' ' -f5 file | paste -d',' -s
+12.0,+15.5,+9.0,+13.5

oder

sed '/^.*\(+[^ ]*\).*/{s//\1/;H};${x;s/\n/,/g;s/.//p};d' file
+12.0,+15.5,+9.0,+13.5

oder

sed 's/\S\+\s\+//;s/\s.*//;H;$!d;x;s/.//;s/\n/,/g' file

Für jede Zeile in der Datei; Das erste Feld und die folgenden Leerzeichen abschneiden, den Rest der Zeile nach dem zweiten Feld abschneiden und an das Haltefeld anhängen. Löschen Sie alle Zeilen außer der letzten, in der wir in den Haltebereich wechseln, und konvertieren Sie nach dem Löschen der eingeführten neuen Zeile zu Beginn alle Zeilen in ,'s.

NB Könnte geschrieben werden:

sed 's/\S\+\s\+//;s/\s.*//;1h;1!H;$!d;x;s/\n/,/g' file

4

Sie können verwenden grep:

grep -o "+\S\+" in.txt | tr '\n' ','

Dabei wird die Zeichenfolge beginnend mit einer +beliebigen Zeichenfolge gefunden \S\+und anschließend neue Zeilenzeichen in Kommas konvertiert. Dies sollte für große Dateien ziemlich schnell gehen.


4

Versuchen Sie diesen einfachen Code:

awk '{printf("%s,",$2)}' File1

3

Versuche dies:

sedSelectNumbers='s".* \(+[0-9]*[.][0-9]*\) .*"\1,"'
sedClearLastComma='s"\(.*\),$"\1"'
cat file.txt |sed "$sedSelectNumbers" |tr -d "\n" |sed "$sedClearLastComma"

Das Gute ist der einfache Teil des Löschens von Zeilenumbrüchen "\ n"!

BEARBEITEN: Eine weitere großartige Möglichkeit, Zeilen mit sed zu einer einzigen Zeile zusammenzufügen, ist folgende: |sed ':a;N;$!ba;s/\n/ /g'Von hier aus .


Diese BEARBEITUNG ist fantastisch - +1!
JoeG

2

Eine Lösung in reinem Bash:

#!/bin/bash

sometext="something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)"

a=()
while read -r a1 a2 a3; do
    # we can add some code here to check valid values or modify them
    a+=("${a2}")
done <<< "${sometext}"
# between parenthesis to modify IFS for the current statement only
(IFS=',' ; printf '%s: %s\n' "Result" "${a[*]}")

Ergebnis: + 12,0, + 15,5, + 9,0, + 13,5


2

Ich habe diese einfache Lösung mit awk nicht gesehen

awk 'b{b=b","}{b=b$2}END{print b}' infile

0

Mit Perl:

fg@erwin ~ $ perl -ne 'push @l, (split(/\s+/))[1]; END { print join(",", @l) . "\n" }' <<EOF
something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)
EOF

+12.0,+15.5,+9.0,+13.5

0

Sie können dies auch mit zwei sed-Anrufen tun:

$ cat file.txt 
something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)
$ sed 's/^[^:]*: *\([+0-9.]\+\) .*/\1/' file.txt | sed -e :a -e '$!N; s/\n/,/; ta'
+12.0,+15.5,+9.0,+13.5

Der erste sed-Aufruf entfernt uninteressante Daten und der zweite verbindet alle Zeilen.


0

Sie können auch folgendermaßen drucken:

Nur awk: mit printf

bash-3.2$ cat sample.log
something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)

bash-3.2$ awk ' { if($2 != "") { if(NR==1) { printf $2 } else { printf "," $2 } } }' sample.log
+12.0,+15.5,+9.0,+13.5

0

Eine weitere Perl-Lösung, ähnlich wie Dan Fegos awk:

perl -ane 'print "$F[1],"' file.txt | sed 's/,$/\n/'

-a Weist Perl an, die Eingabezeile in das @ F-Array aufzuteilen, das ab 0 indiziert wird.


0

Nun, der schwierigste Teil ist wahrscheinlich die Auswahl der zweiten "Spalte", da ich keine einfache Möglichkeit kennen würde, mehrere Leerzeichen als ein Leerzeichen zu behandeln. Für den Rest ist es einfach. Verwenden Sie Bash-Substitutionen.

# cat bla.txt
something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)

# cat bla.sh
OLDIFS=$IFS
IFS=$'\n'
for i in $(cat bla.txt); do
  i=$(echo "$i" | awk '{print $2}')
  u="${u:+$u, }$i"
done
IFS=$OLDIFS
echo "$u"

# bash ./bla.sh
+12.0, +15.5, +9.0, +13.5
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.