Перетворення багаторядкового рядка в єдину, розділену комами


95

Скажімо, у мене є такий рядок:

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 як мови програмування. Розглянемо Скалу listOfStuff mkString ", ", або Хаскеллаintercalate ", " listOfString
FP Вільно

Відповіді:


92

Ви можете використовувати 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: invalid -v option :(
Marsellus Wallace

6
Додайте пробіл між -v та ORS =, (для мене, на osx)
Graham P Heath

Як виконати ту саму команду для розділення труби? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'я отримую помилку
Йогеш

2
дивним чином, коли я намагаюся це зробити, вихід не пустий.
forevertyro

1
Я думаю, що для конвеєрної версії це повинно бути {print $1}інакше, я отримую лише коми у вихідних даних
Перемислав Чеховський

162

Чисто і просто:

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

3
Це найкраща відповідь тут, і, очевидно, правильний спосіб це зробити
forresthopkinsa

Як мені процитувати всі значення за допомогою одинарної / подвійної лапки?
Хуссен

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

Як використовувати ,'як роздільник?
Касун Сіямбалапітія

Не забувайте обробляти нові рядки Windows (наприклад, використовуючи dos2unix), якщо в рядку є CRLF.
Бові


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



8

Це може підійти вам:

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'got from here .


Це РЕДАГУВАТИ чудово - +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


2

Не бачив цього простого рішення з awk

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

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

Ви також можете зробити це за допомогою двох дзвінків 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

Перший дзвінок sed видаляє нецікаві дані, а другий приєднує всі рядки.


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 Дана Фего:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.