Çok satırlı dizeyi tek virgülle ayrılmış hale getirme


102

Diyelim ki şu dizeye sahibim:

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)

Bunu nasıl basitleştirebilirim

+12.0,+15.5,+9.0,+13.5

bash'da?


Bir an için geri adım atalım ve bu konuyu programlama dili olarak bash'ın apaçık bir suçlaması olarak ele alalım. Scala's listOfStuff mkString ", "veya Haskell'sintercalate ", " listOfString
Serbestçe

Yanıtlar:


95

Sen kullanabilirsiniz awkve sed:

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

Veya bir boru kullanmak istiyorsanız:

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

Parçalamak için:

  • awk alanlara bölünmüş verileri işlemede harikadır
  • -vORS=,"çıktı kaydı ayırıcısını" ,, istediğiniz gibi ayarlar
  • { print $2 }awkher kayıt (satır) için ikinci alanı yazdırmayı söyler
  • file.txt dosya adınız
  • sedsadece sondan kurtulur ,ve onu yeni bir satıra dönüştürür (yeni satır istemiyorsanız, yapabilirsiniz s/,$//)

1
awk: geçersiz -v seçenek :(
Marsellus Wallace

7
-V ve ORS = arasında bir boşluk ekleyin (benim için osx'te)
Graham P Heath

Boruyu ayırmak için aynı komut nasıl yapılır? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'bir hata alıyorum
Yogesh

3
Garip bir şekilde, bunu yapmaya çalıştığımda çıktı boş.
eternaltyro

1
Sanırım borulu sürüm için, {print $1}aksi takdirde çıktıda yalnızca virgül alıyorum
Przemysław Czechowski

171

Temiz ve basit:

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

5
Buradaki en iyi cevap ve tabii ki bunu yapmanın doğru yolu
forresthopkinsa

Her değeri tek / çift tırnakla nasıl alıntılayabilirim?
Hussain

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

,'Sınırlayıcı olarak nasıl kullanılır ?
Kasun Siyambalapitiya

Dizede herhangi bir CRLF varsa Windows yeni satırlarını işlemeyi (örneğin kullanarak dos2unix) unutmayın.
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

şerefe, ya function | awk...
awk'a

10

awk tek astar

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

+12.0,+15.5,+9.0,+13.5

Biçim belirteci "%s",, printfdaha sağlam hale getirmek, yani "foo% s" gibi her tür satırla çalışmasını sağlamak için sonrasına eklenmelidir .
jarno

10

Bu sizin için işe yarayabilir:

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

veya

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

veya

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

Dosyadaki her satır için; İlk alanı ve arkasındaki boşlukları kesin, ikinci alanı izleyen satırın kalanını kesin ve muhafaza alanına ekleyin. Bekletme alanına en son değiştirdiğimiz yer hariç tüm satırları silin ve başlangıçta eklenen yeni satırı sildikten sonra, tüm yeni satırları ,'s' e dönüştürün .

NB yazılabilir:

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


4

Şunları kullanabilirsiniz grep:

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

ile başlayan +dizeyi \S\+ve ardından herhangi bir dizeyi bulur , ardından yeni satır karakterlerini virgüllere dönüştürür. Bu, büyük dosyalar için oldukça hızlı olmalıdır.


4

Bu kolay kodu deneyin:

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

Fazladan bir virgül ekler
jarno

3

bunu dene:

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

iyi olan şey, yeni satır "\ n" karakterlerini silmenin kolay kısmıdır!

DÜZENLEME: sed ile tek bir satır içine çizgileri katılmak için bir başka yoldur şudur: |sed ':a;N;$!ba;s/\n/ /g'aldığım burada .


Bu DÜZENLEME harika - +1!
JoeG

2

Saf Bash ile yazılmış bir çözüm:

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

Sonuç: + 12.0, + 15.5, + 9.0, + 13.5


Alternatif olarak kullanabilir read -r -a colsve daha sonra "${cols[1]}listeye ekleyebilirsiniz a.
jarno

2

Awk ile bu basit çözümü görmedim

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

0

Perl ile:

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

Bunu iki sed aramayla da yapabilirsiniz:

$ 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

İlk sed çağrısı ilginç olmayan verileri kaldırır ve ikincisi tüm hatları birleştirir.


0

Ayrıca şu şekilde yazdırabilirsiniz:

Sadece awk: printf kullanarak

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

Dan Fego'nun awk'sine benzer başka bir Perl çözümü:

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

-a perl'e giriş satırını 0'dan başlayarak indekslenen @F dizisine bölmesini söyler.


0

Muhtemelen en zor kısım ikinci "sütunu" seçmektir çünkü birden fazla alanı tek bir alan olarak ele almanın kolay bir yolunu bilmiyordum. Geri kalanı için çok kolay. Bash ikamelerini kullanın.

# 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

0

Yine başka bir AWK çözümü

Çalıştırmak

awk '{printf "%s", $c; while(getline){printf "%s%s", sep, $c}}' c=2 sep=','

virgülle ayrılmış listeyi oluşturmak için 2. sütunu kullanmak için. Girişi her zamanki gibi standart girdide veya bir dosya adı bağımsız değişkeni olarak verin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.