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?

Alex Coplan
quelle
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/,$//)
Dan Fego
quelle
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, -
Mattias Ahnberg
quelle
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
20
cat data.txt | xargs | sed -e 's/ /, /g'
Bhargav Srinivasan
quelle
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
kev
quelle
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
Rahul Verma
quelle
8

Das sollte auch funktionieren

awk '{print $2}' file | sed ':a;{N;s/\n/,/};ba'
jaypal singh
quelle
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
Potong
quelle
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.

Kenorb
quelle
4

Versuchen Sie diesen einfachen Code:

awk '{printf("%s,",$2)}' File1
Vonton
quelle
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 .

Wassermann-Kraft
quelle
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

Quatro por Quatro
quelle
2

Ich habe diese einfache Lösung mit awk nicht gesehen

awk 'b{b=b","}{b=b$2}END{print b}' infile
ctac_
quelle
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
fge
quelle
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.

Elias Dorneles
quelle
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

quelle
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.

Chris Koknat
quelle
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
Marki
quelle