การเปลี่ยนสตริงหลายบรรทัดเป็นคั่นด้วยจุลภาคเดียว


102

สมมติว่าฉันมีสตริงต่อไปนี้:

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)

ฉันจะเปลี่ยนมันให้เป็นแบบง่ายๆได้อย่างไร

+12.0,+15.5,+9.0,+13.5

ทุบตี?


ลองย้อนกลับไปสักครู่และพิจารณาว่าเธรดนี้เป็นคำฟ้องที่ชัดเจนของ bash เป็นภาษาโปรแกรม พิจารณาของ Scala listOfStuff mkString ", "หรือ Haskell'sintercalate ", " listOfString
FP ได้อย่างอิสระ

คำตอบ:


95

คุณสามารถใช้awkและsed:

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

หรือหากคุณต้องการใช้ท่อ:

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

ในการทำลายมันลง:

  • awk มีความยอดเยี่ยมในการจัดการข้อมูลที่แยกย่อยออกเป็นช่องต่างๆ
  • -vORS=,ตั้งค่า "ตัวคั่นเร็กคอร์ดเอาต์พุต" เป็น,ซึ่งเป็นสิ่งที่คุณต้องการ
  • { print $2 } บอก awkให้พิมพ์ฟิลด์ที่สองสำหรับทุกระเบียน (บรรทัด)
  • file.txt คือชื่อไฟล์ของคุณ
  • sedเพียงแค่กำจัดการต่อท้าย,และเปลี่ยนเป็นบรรทัดใหม่ (หากคุณไม่ต้องการขึ้นบรรทัดใหม่คุณสามารถทำได้s/,$//)

1
awk: ไม่ถูกต้องตัวเลือก -v :(
Marsellus Wallace

7
เพิ่มช่องว่างระหว่าง -v และ ORS = (สำหรับฉันบน osx)
Graham P Heath

จะทำอย่างไรคำสั่งเดียวกันสำหรับการแยกท่อ awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'ฉันได้รับข้อผิดพลาด
Yogesh

3
น่าแปลกที่เมื่อฉันพยายามทำสิ่งนี้ผลลัพธ์จะว่างเปล่า
eternaltyro

1
ฉันคิดว่าสำหรับเวอร์ชัน piped ควรเป็น{print $1}อย่างอื่นฉันจะได้รับเครื่องหมายจุลภาคเท่านั้นในเอาต์พุต
Przemysław Czechowski

171

สะอาดและเรียบง่าย:

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

5
นี่คือคำตอบที่ดีที่สุดที่นี่และเห็นได้ชัดว่าเป็นวิธีที่ถูกต้องในการทำเช่นนี้
forresthopkinsa

ฉันจะอ้างอิงทุกค่าด้วยเครื่องหมายคำพูดเดี่ยว / คู่ได้อย่างไร
Hussain

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

ใช้,'เป็นตัวคั่นอย่างไร
Kasun Siyambalapitiya

อย่าลืมจัดการWindows newlines (เช่นการใช้dos2unix) หากมี CRLF ในสตริง
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

ไชโยถ้าอินพุตไปยัง awk ผ่านอินพุตมาตรฐาน (ใส่function | awk...ในตัวอย่างของคุณเท่านั้น
Alex Coplan

10

awkหนึ่งซับ

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

+12.0,+15.5,+9.0,+13.5

"%s",ควรเพิ่มตัวระบุรูปแบบหลังprintfเพื่อให้มีประสิทธิภาพมากขึ้นเช่นทำให้ทำงานได้กับแถวทุกประเภทเช่น "foo% s"
jarno

10

สิ่งนี้อาจได้ผลสำหรับคุณ:

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

หรือ

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

หรือ

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

สำหรับแต่ละบรรทัดในไฟล์ ตัดฟิลด์แรกและช่องว่างต่อจากนั้นตัดส่วนที่เหลือของบรรทัดถัดจากฟิลด์ที่สองและต่อท้ายด้วยช่องว่าง ลบบรรทัดทั้งหมดยกเว้นบรรทัดสุดท้ายที่เราสลับไปยังพื้นที่พักและหลังจากลบบรรทัดใหม่ที่แนะนำเมื่อเริ่มต้นแล้วให้แปลงบรรทัดใหม่ทั้งหมดเป็น, 's

NB สามารถเขียนได้:

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


4

คุณสามารถใช้grep:

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

ซึ่งค้นหาสตริงที่ขึ้นต้นด้วย+ตามด้วยสตริงใด ๆ\S\+จากนั้นแปลงอักขระบรรทัดใหม่เป็นลูกน้ำ สิ่งนี้ควรจะค่อนข้างเร็วสำหรับไฟล์ขนาดใหญ่



3

ลองสิ่งนี้:

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

สิ่งที่ดีคือส่วนที่ง่ายในการลบอักขระ "\ n" ขึ้นบรรทัดใหม่!

แก้ไข: อีกวิธีที่ดีที่จะเข้าร่วมเป็นเส้นบรรทัดเดียวกับ sed คือ: |sed ':a;N;$!ba;s/\n/ /g'ได้จากที่นี่


การแก้ไขนั้นยอดเยี่ยม - +1!
JoeG

2

คำตอบที่เขียนด้วย 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[*]}")

ผลลัพธ์: + 12.0, + 15.5, + 9.0, + 13.5


หรือคุณสามารถใช้read -r -a colsและหลังจากนั้นเพิ่มในรายการ"${cols[1]} a
jarno


0

ด้วย 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

คุณสามารถทำได้ด้วยการโทรสองครั้ง:

$ 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

การโทรครั้งแรกจะลบข้อมูลที่ไม่น่าสนใจและครั้งที่สองจะเข้าร่วมทุกบรรทัด


0

คุณยังสามารถพิมพ์ได้ดังนี้:

เพียงแค่ awk: โดยใช้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

โซลูชัน Perl อื่นที่คล้ายกับ awk ของ Dan Fego:

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

-a บอกให้ perl แยกบรรทัดอินพุตลงในอาร์เรย์ @F ซึ่งจัดทำดัชนีเริ่มต้นที่ 0


0

ส่วนที่ยากที่สุดน่าจะเป็นการเลือก "คอลัมน์" ที่สองเนื่องจากฉันไม่รู้วิธีง่ายๆในการจัดการช่องว่างหลายช่องให้เป็นหนึ่งเดียว สำหรับส่วนที่เหลือเป็นเรื่องง่าย ใช้การแทนที่ 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

0

อีกหนึ่งโซลูชัน AWK

วิ่ง

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

เพื่อใช้คอลัมน์ที่ 2 เพื่อสร้างรายการโดยคั่นด้วยเครื่องหมายจุลภาค ให้อินพุตตามปกติในอินพุตมาตรฐานหรือเป็นอาร์กิวเมนต์ชื่อไฟล์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.