Mengubah string multi-baris menjadi satu dipisahkan koma


95

Katakanlah saya memiliki string berikut:

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)

Bagaimana cara mengubahnya menjadi sederhana

+12.0,+15.5,+9.0,+13.5

dalam pesta?


Mari mundur sejenak dan anggap utas ini sebagai dakwaan mencolok tentang bash sebagai bahasa pemrograman. Pertimbangkan Scala's listOfStuff mkString ", ", atau Haskell'sintercalate ", " listOfString
FP Freely

Jawaban:


92

Anda dapat menggunakan awkdan sed:

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

Atau jika Anda ingin menggunakan pipa:

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

Untuk memecahnya:

  • awk sangat bagus dalam menangani data yang dipecah menjadi beberapa bidang
  • -vORS=,setel "pemisah rekaman keluaran" ke ,, yang Anda inginkan
  • { print $2 }memberitahu awkuntuk mencetak bidang kedua untuk setiap catatan (baris)
  • file.txt adalah nama file Anda
  • sedhanya menghilangkan trailing ,dan mengubahnya menjadi baris baru (jika Anda tidak menginginkan baris baru, Anda bisa melakukannya s/,$//)

1
awk: opsi -v tidak valid :(
Marsellus Wallace

6
Tambahkan spasi antara -v dan ORS =, (untuk saya, di osx)
Graham P Heath

Bagaimana cara melakukan perintah yang sama untuk memisahkan pipa? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'saya mendapatkan kesalahan
Yogesh

2
anehnya, ketika saya mencoba melakukan ini, hasilnya kosong.
eternaltyro

1
Saya pikir untuk versi perpipaan seharusnya {print $1}sebaliknya saya hanya mendapatkan koma dalam keluaran
Przemysław Czechowski

162

Bersih dan sederhana:

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

3
Ini adalah jawaban terbaik di sini, dan jelas cara yang benar untuk melakukannya
forresthopkinsa

Bagaimana cara mengutip setiap nilai dengan tanda kutip tunggal / ganda?
Hussain

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

Bagaimana digunakan ,'sebagai pembatas?
Kasun Siyambalapitiya

Ingatlah untuk menangani baris baru Windows (misalnya menggunakan dos2unix) jika ada CRLF dalam string tersebut.
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

cheers, bagaimana jika input ke awk melalui input standar (masukkan saja ke function | awk...dalam contoh anda?
Alex Coplan

10

awk satu kapal

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

+12.0,+15.5,+9.0,+13.5


8

Ini mungkin berhasil untuk Anda:

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

atau

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

atau

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

Untuk setiap baris dalam file; potong bidang pertama dan spasi setelahnya, potong sisa baris setelah bidang kedua dan tambahkan ke ruang tunggu. Hapus semua baris kecuali yang terakhir tempat kita menukar ke ruang tunggu dan setelah menghapus baris baru yang diperkenalkan di awal, ubah semua baris baru menjadi ,.

NB Bisa ditulis:

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

4

Anda dapat menggunakan grep:

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

yang menemukan string dimulai dengan +, diikuti dengan string apa pun \S\+, lalu mengubah karakter baris baru menjadi koma. Ini seharusnya cukup cepat untuk file besar.


4

Coba kode mudah ini:

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

3

coba ini:

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

hal baiknya adalah bagian yang mudah dari menghapus karakter "\ n" baris baru!

EDIT: cara hebat lain untuk menggabungkan garis menjadi satu baris dengan sed adalah ini: |sed ':a;N;$!ba;s/\n/ /g'dapatkan dari sini .


EDIT itu luar biasa - +1!
JoeG

2

Solusi yang ditulis dalam Bash murni:

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

Hasil: + 12.0, + 15.5, + 9.0, + 13.5


2

Jangan melihat solusi sederhana ini dengan awk

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

0

Dengan 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

Anda juga dapat melakukannya dengan dua panggilan sed:

$ 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

Panggilan sed pertama menghapus data yang tidak menarik, dan yang kedua menggabungkan semua baris.


0

Anda juga dapat mencetak seperti ini:

Just awk: menggunakan 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

Solusi Perl lainnya, mirip dengan awk Dan Fego:

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

-a memberi tahu perl untuk membagi baris input menjadi larik @F, yang diindeks mulai dari 0.


0

Bagian tersulit mungkin adalah memilih "kolom" kedua karena saya tidak tahu cara mudah untuk memperlakukan banyak spasi sebagai satu. Selebihnya mudah saja. Gunakan substitusi bash.

# 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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.