Chuyển chuỗi nhiều dòng thành một chuỗi được phân tách bằng dấu phẩy


95

Giả sử tôi có chuỗi sau:

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)

Làm cách nào để biến điều đó thành đơn giản

+12.0,+15.5,+9.0,+13.5

trong bash?


Hãy lùi lại một chút và coi chuỗi này là một bản cáo trạng rõ ràng về bash như một ngôn ngữ lập trình. Hãy xem xét Scala's listOfStuff mkString ", ", hoặc Haskell'sintercalate ", " listOfString
FP Freely

Câu trả lời:


92

Bạn có thể sử dụng awksed:

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

Hoặc nếu bạn muốn sử dụng tẩu:

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

Để phá vỡ nó:

  • awk rất giỏi trong việc xử lý dữ liệu được chia nhỏ thành các trường
  • -vORS=,đặt "dấu phân tách bản ghi đầu ra" ,, đó là những gì bạn muốn
  • { print $2 }yêu awkcầu in trường thứ hai cho mọi bản ghi (dòng)
  • file.txt là tên tệp của bạn
  • sedchỉ cần loại bỏ dấu vết ,và biến nó thành một dòng mới (nếu bạn không muốn có dòng mới, bạn có thể làm s/,$//)

1
awk: tùy chọn -v không hợp lệ :(
Marsellus Wallace

6
Thêm một không gian giữa -v và ORS =, (đối với tôi, trên OSX)
Graham P Heath

Làm thế nào để thực hiện lệnh tương tự để tách đường ống? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'đang gặp lỗi
Yogesh

2
kỳ lạ, khi tôi cố gắng làm điều này, đầu ra là trống.
forevertyro

1
Tôi nghĩ rằng đối với phiên bản đường ống, nó phải là {print $1}nếu không, tôi chỉ nhận được dấu phẩy trong đầu ra
Przemysław Czechowski

162

Sạch sẽ và đơn giản:

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

3
Đây là câu trả lời tốt nhất ở đây, và rõ ràng là cách chính xác để làm điều này
forresthopkinsa

Làm cách nào để trích dẫn mọi giá trị bằng dấu nháy đơn / kép?
Hussain

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

Làm thế nào để sử dụng ,'làm dấu phân cách?
Kasun Siyambalapitiya

Hãy nhớ xử lý các dòng mới của Windows (ví dụ: sử dụng dos2unix) nếu có bất kỳ CRLF nào trong chuỗi.
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

cổ vũ, những gì về nếu đầu vào awk đã được thông qua đầu vào tiêu chuẩn (chỉ cần đặt function | awk...trong ví dụ của bạn?
Alex Coplan

10

awk một lớp lót

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

+12.0,+15.5,+9.0,+13.5

8

Điều này cũng nên hoạt động

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

8

Điều này có thể làm việc cho bạn:

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

hoặc là

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

hoặc là

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

Đối với mỗi dòng trong tệp; cắt trường đầu tiên và các khoảng trắng theo sau, cắt phần còn lại của dòng theo sau trường thứ hai và thêm vào khoảng trống. Xóa tất cả các dòng ngoại trừ dòng cuối cùng mà chúng tôi hoán đổi thành không gian lưu giữ và sau khi xóa dòng mới đã giới thiệu ở đầu, hãy chuyển đổi tất cả các dòng mới thành, 's.

NB Có thể được viết:

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

4

Bạn có thể sử dụng grep:

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

tìm chuỗi bắt đầu bằng +, theo sau là bất kỳ chuỗi nào \S\+, sau đó chuyển đổi các ký tự dòng mới thành dấu phẩy. Điều này sẽ khá nhanh chóng đối với các tệp lớn.


4

Hãy thử mã dễ dàng này:

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

3

thử cái này:

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

điều tốt là phần dễ dàng xóa các ký tự "\ n" ở dòng mới!

CHỈNH SỬA: một cách tuyệt vời khác để nối các dòng thành một dòng duy nhất với sed là this: |sed ':a;N;$!ba;s/\n/ /g'got from here .


EDIT đó thật tuyệt vời - +1!
JoeG

2

Một giải pháp được viết bằng Bash tinh khiết:

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

Kết quả: + 12.0, + 15.5, + 9.0, + 13.5


2

Không thấy giải pháp đơn giản này với awk

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

0

Với 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

Bạn cũng có thể làm điều đó với hai cuộc gọi 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

Cuộc gọi sed đầu tiên loại bỏ dữ liệu không quan tâm và cuộc gọi thứ hai nối tất cả các dòng.


0

Bạn cũng có thể in như thế này:

Chỉ cần awk: sử dụng 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

Một giải pháp Perl khác, tương tự như awk của Dan Fego:

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

-a yêu cầu perl tách dòng đầu vào thành mảng @F, được lập chỉ mục bắt đầu từ 0.


0

Chà, phần khó nhất có lẽ là chọn "cột" thứ hai vì tôi không biết một cách dễ dàng để coi nhiều khoảng trắng là một. Đối với phần còn lại, thật dễ dàng. Sử dụng thay thế 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.