Превращение многострочной строки в одиночную, разделенную запятыми

99

Скажем, у меня есть следующая строка:

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 Freely

Ответы:

94

Вы можете использовать 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 :(
Марселлус Уоллес
6
Добавьте пробел между -v и ORS =, (для меня, на osx)
Грэм П. Хит
Как выполнить ту же команду для разделения трубы? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'я получаю сообщение об ошибке
Йогеш
2
как ни странно, когда я пытаюсь это сделать, вывод оказывается пустым.
eternaltyro
1
Я думаю, что для конвейерной версии это должно быть {print $1}иначе, я получаю только запятые на выходе
Пшемыслав Чеховски
167

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

awk '{print $2}' file.txt | paste -s -d, -
Маттиас Анберг
источник
5
Это лучший ответ здесь и, очевидно, правильный способ сделать это
forresthopkinsa
Как указать каждое значение в одинарной / двойной кавычке?
Хуссейн
2
@Hussaincat thing | awk -F',' '{ print "'\''" $7 "'\' '" }' | paste -s -d ','
starbeamrainbowlabs
Как использовать ,'в качестве разделителя?
Касун Сиямбалапития
Не забывайте обрабатывать символы новой строки Windows (например, используя dos2unix), если в строке есть какие-либо CRLF.
Bowi
19
cat data.txt | xargs | sed -e 's/ /, /g'
Бхаргав Шринивасан
источник
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...свой пример?
Алекс Коплан,
10

awk один лайнер

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

+12.0,+15.5,+9.0,+13.5
Рахул Верма
источник
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
Potong
источник
8

Это тоже должно работать

awk '{print $2}' file | sed ':a;{N;s/\n/,/};ba'
Джайпал Сингх
источник
4

Вы можете использовать grep:

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

который находит строку, начинающуюся с +, за которой следует любая строка \S\+, а затем преобразует символы новой строки в запятые. Это должно быть довольно быстро для больших файлов.

Kenorb
источник
4

Попробуйте этот простой код:

awk '{printf("%s,",$2)}' File1
Вонтон
источник
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

Quatro por Quatro
источник
2

Не видел этого простого решения с awk

awk 'b{b=b","}{b=b$2}END{print b}' infile
ctac_
источник
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
fge
источник
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
Марки
источник