Лаконичное и переносимое «соединение» в командной строке Unix - PullRequest
71 голосов
/ 15 декабря 2011

Как можно объединить несколько строк в одну строку с разделителем, в котором находились символы новой строки, и избегая конечного разделителя и, при необходимости, игнорировать пустые строки?

Пример.Рассмотрим текстовый файл foo.txt с тремя строками:

foo
bar
baz

Требуемый вывод:

foo,bar,baz

Используемая сейчас команда:

tr '\n' ',' <foo.txt |sed 's/,$//g'

В идеале это будет примерно так:

cat foo.txt |join ,

Что такое:

  1. самый портативный, лаконичный, читаемый способ.
  2. самый лаконичный способиспользуя нестандартные инструменты Unix.

Конечно, я мог бы написать что-нибудь или просто использовать псевдоним.Но мне интересно узнать варианты.

Ответы [ 9 ]

117 голосов
/ 15 декабря 2011

Возможно, немного удивительно, paste - хороший способ сделать это:

paste -s -d","

Это не будет иметь дело с упомянутыми вами пустыми строками.Для этого перенаправьте текст через grep, сначала:

grep -v '^$' | paste -s -d"," -
12 голосов
/ 15 декабря 2011

Эта sed одна строка должна работать -

sed -e :a -e 'N;s/\n/,/;ba' file

Тест:

[jaypal:~/Temp] cat file
foo
bar
baz

[jaypal:~/Temp] sed -e :a -e 'N;s/\n/,/;ba' file
foo,bar,baz

Чтобы обработать пустые строки, вы можете удалить пустые строки и направить их на вышеуказанную строку.

sed -e '/^$/d' file | sed -e :a -e 'N;s/\n/,/;ba'
8 голосов
/ 29 июля 2015

Как насчет использования xargs?

для вашего случая

$ cat foo.txt | sed 's/$/, /' | xargs

Будьте осторожны с предельной длиной ввода команды xargs. (Это означает, что очень длинный входной файл не может быть обработан этим.)

6 голосов
/ 17 июня 2014

Perl:

cat data.txt | perl -pe 'if(!eof){chomp;$_.=","}'

или еще короче и быстрее, на удивление:

cat data.txt | perl -pe 'if(!eof){s/\n/,/}'

или, если хотите:

cat data.txt | perl -pe 's/\n/,/ unless eof'
4 голосов
/ 15 декабря 2011

Просто для удовольствия, вот полностью встроенное решение

IFS=$'\n' read -r -d '' -a data < foo.txt ; ( IFS=, ; echo "${data[*]}" ; )

Вы можете использовать printf вместо echo, если завершающий перевод строки является проблемой.

Это работаетустановив IFS, разделители, на которые будет разделяться read, просто на новую строку, а не на другие пробелы, затем сообщая read не прекращать чтение, пока оно не достигнет nul, вместо обычно используемой новой строки,добавить каждый прочитанный элемент в массив (-a) данных.Затем в подоболочке, чтобы не загромождать IFS интерактивной оболочки, мы устанавливаем IFS в , и расширяем массив с помощью *, который разделяет каждый элемент в массиве первым символом в IFS

0 голосов
/ 28 января 2016

Мой ответ:

awk '{printf "%s", ","$0}' foo.txt

printf достаточно. Нам не нужно -F"\n" для изменения разделителя полей.

0 голосов
/ 11 декабря 2015

У меня был файл журнала, в котором некоторые данные были разбиты на несколько строк.Когда это произошло, последним символом первой строки была точка с запятой (;).Я присоединился к этим строкам с помощью следующих команд:

for LINE in 'cat $FILE | tr -s " " "|"'
do
    if [ $(echo $LINE | egrep ";$") ]
    then
        echo "$LINE\c" | tr -s "|" " " >> $MYFILE
    else
        echo "$LINE" | tr -s "|" " " >> $MYFILE
    fi
done

В результате получается файл, в котором строки, разделенные в файле журнала, были одной строкой в ​​моем новом файле.

0 голосов
/ 30 мая 2015

Простой способ объединить строки с пробелами на месте, используя ex (также игнорируя пустые строки), используйте:

ex +%j -cwq foo.txt

Если вы хотите напечатать результаты в стандартный вывод, попробуйте:

ex +%j +%p -scq! foo.txt

Чтобы объединить строки без пробелов, используйте +%j! вместо +%j.

Чтобы использовать другой разделитель, это немного сложнее:

ex +"g/^$/d" +"%s/\n/_/e" +%p -scq! foo.txt

где g/^$/d (или v/\S/d) удаляет пустые строки, а s/\n/_/ - это подстановка, которая в основном работает так же, как при использовании sed, но для всех строк (%).Когда синтаксический анализ завершен, выведите буфер (%p).И, наконец, -cq! выполняет команду vi q!, которая в основном завершается без сохранения (-s означает отключение вывода).

Обратите внимание, что ex эквивалентно vi -e.

Этот метод довольно переносим, ​​так как большинство Linux / Unix поставляются с ex / vi по умолчанию.И это более совместимо, чем использование sed, где параметр на месте (-i) не является стандартным расширением, а утилита сама по себе более ориентирована на поток, поэтому она не так переносима.

0 голосов
/ 06 ноября 2013

Мне нужно было сделать что-то похожее, распечатать список полей через запятую из файла, и я был доволен передачей STDOUT в xargs и ruby, например:

cat data.txt | cut -f 16 -d ' ' | grep -o "\d\+" | xargs ruby -e "puts ARGV.join(', ')"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...