Zamiana wielowierszowego ciągu na pojedynczy oddzielony przecinkami

99

Powiedzmy, że mam następujący ciąg:

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)

Jak zmienić to w proste

+12.0,+15.5,+9.0,+13.5

w bash?

Alex Coplan
źródło
Cofnijmy się na chwilę i potraktujmy ten wątek jako rażące oskarżenie basha jako języka programowania. Weźmy pod uwagę Scalę listOfStuff mkString ", "lub Haskellaintercalate ", " listOfString
FP Freely

Odpowiedzi:

94

Możesz użyć awki sed:

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

Lub jeśli chcesz użyć rury:

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

Aby to rozbić:

  • awk świetnie radzi sobie z danymi podzielonymi na pola
  • -vORS=,ustawia „separator rekordów wyjściowych” na ,, co chcesz
  • { print $2 }nakazuje awkwydrukować drugie pole dla każdego rekordu (wiersza)
  • file.txt to twoja nazwa pliku
  • sedpo prostu pozbywa się końcowego ,i zamienia go w nową linię (jeśli nie chcesz nowej linii, możesz to zrobić s/,$//)
Dan Fego
źródło
1
awk: invalid -v opcja :(
Marsellus Wallace
6
Dodaj spację między -v i ORS =, (dla mnie na osx)
Graham P Heath
Jak wykonać to samo polecenie, aby rozdzielić potok? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'pojawia się błąd
Yogesh
2
dziwnie, kiedy próbuję to zrobić, wyjście jest puste.
eternaltyro
1
Myślę, że dla wersji potokowej powinno być {print $1}inaczej na wyjściu otrzymuję tylko przecinki
Przemysław Czechowski
164

Czyste i proste:

awk '{print $2}' file.txt | paste -s -d, -
Mattias Ahnberg
źródło
4
To jest najlepsza odpowiedź tutaj i oczywiście właściwy sposób na zrobienie tego
forresthopkinsa
Jak zacytować wszystkie wartości za pomocą pojedynczego / podwójnego cudzysłowu?
Hussain
2
@Hussaincat thing | awk -F',' '{ print "'\''" $7 "'\' '" }' | paste -s -d ','
starbeamrainbowlabs
Jak używać ,'jako separatora?
Kasun Siyambalapitiya
Pamiętaj, aby obsługiwać znaki nowej linii Windows (np. Używając dos2unix), jeśli w ciągu znajdują się CRLF.
Bowi
19
cat data.txt | xargs | sed -e 's/ /, /g'
Bhargav Srinivasan
źródło
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
źródło
Pozdrawiam, a co by było, gdyby dane wejściowe do awk przechodziły przez standardowe wejście (wystarczy function | awk...podać przykład?
Alex Coplan
10

awk one liner

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

+12.0,+15.5,+9.0,+13.5
Rahul Verma
źródło
9

To może Ci pomóc:

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

lub

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

lub

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

Dla każdego wiersza w pliku; odetnij pierwsze pole i następne spacje, odetnij pozostałą część linii po drugim polu i dołącz do przestrzeni ładunkowej. Usuń wszystkie linie z wyjątkiem ostatniej, w której zamieniamy się w miejsce przechowywania i po usunięciu wprowadzonego znaku nowej linii na początku, przekonwertuj wszystkie nowe wiersze na ,.

NB Można napisać:

sed 's/\S\+\s\+//;s/\s.*//;1h;1!H;$!d;x;s/\n/,/g' file
potong
źródło
8

To też powinno działać

awk '{print $2}' file | sed ':a;{N;s/\n/,/};ba'
jaypal singh
źródło
4

Możesz użyć grep:

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

który znajduje ciąg zaczynający się od +, po którym następuje dowolny ciąg \S\+, a następnie konwertuje znaki nowego wiersza na przecinki. Powinno to być dość szybkie w przypadku dużych plików.

kenorb
źródło
4

Wypróbuj ten prosty kod:

awk '{printf("%s,",$2)}' File1
Vonton
źródło
3

Spróbuj tego:

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

dobrą rzeczą jest łatwa część usuwania znaków nowego wiersza "\ n"!

EDYCJA: kolejny świetny sposób na połączenie linii w jedną linię za pomocą seda to: |sed ':a;N;$!ba;s/\n/ /g'dostałem stąd .

Moc Wodnika
źródło
Ta EDYCJA jest niesamowita - +1!
JoeG,
2

Rozwiązanie napisane czystym bashem:

#!/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[*]}")

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

Quatro por Quatro
źródło
2

Nie widziałem tego prostego rozwiązania w awk

awk 'b{b=b","}{b=b$2}END{print b}' infile
ctac_
źródło
0

Z perlem:

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
źródło
0

Możesz to również zrobić za pomocą dwóch wywołań seda:

$ 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

Pierwsze wywołanie sed usuwa nieciekawe dane, a drugie łączy wszystkie linie.

Elias Dorneles
źródło
0

Możesz również drukować w ten sposób:

Po prostu awk: używając 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

źródło
0

Inne rozwiązanie Perla, podobne do awk Dana Fego:

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

-a mówi perlowi, aby podzielił wiersz wejściowy na tablicę @F, która jest indeksowana począwszy od 0.

Chris Koknat
źródło
0

Cóż, najtrudniejszą częścią jest prawdopodobnie wybranie drugiej „kolumny”, ponieważ nie znałbym łatwego sposobu traktowania wielu spacji jako jednej. Reszta jest łatwa. Użyj podstawień basha.

# 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
źródło