Ответ 1
Возможно, немного удивительно, paste
- хороший способ сделать это:
paste -s -d","
Это не касается пустых строк, которые вы упомянули. Для этого проведите текст через grep
, сначала:
grep -v '^$' | paste -s -d"," -
Как я могу объединить несколько строк в одну строку с разделителем, где были символы новой строки, и избегать трейлинг-разделителя и, необязательно, игнорировать пустые строки?
Пример. Рассмотрим текстовый файл foo.txt
с тремя строками:
foo
bar
baz
Требуемый результат:
foo,bar,baz
Команда, которую я сейчас использую:
tr '\n' ',' <foo.txt |sed 's/,$//g'
В идеале это будет примерно так:
cat foo.txt |join ,
Что:
Конечно, я мог бы написать что-нибудь или просто использовать псевдоним. Но мне интересно знать варианты.
Возможно, немного удивительно, paste
- хороший способ сделать это:
paste -s -d","
Это не касается пустых строк, которые вы упомянули. Для этого проведите текст через grep
, сначала:
grep -v '^$' | paste -s -d"," -
Эта 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'
Как использовать xargs?
для вашего случая
$ cat foo.txt | sed 's/$/, /' | xargs
Соблюдайте предельную длину ввода команды xargs. (Это означает, что очень длинный входной файл не может быть обработан этим.)
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'
Просто для удовольствия, здесь решение all-builtins
IFS=$'\n' read -r -d '' -a data < foo.txt ; ( IFS=, ; echo "${data[*]}" ; )
Вы можете использовать printf
вместо echo
, если конечная новая строка является проблемой.
Это работает, установив IFS
, разделители, которые read
будут разделены, только на новую строку, а не на другие пробелы, а затем сообщают read
не прекращать чтение, пока не достигнут nul
, вместо новой строки он обычно использует и добавляет каждый элемент, считываемый в данные массива (-a
). Затем в подоболочке, чтобы не сжимать IFS
интерактивной оболочки, мы устанавливаем IFS
в ,
и расширяем массив с помощью *
, который ограничивает каждый элемент массива первым символом в IFS
Мне нужно было сделать что-то подобное, распечатав список полей, разделенных запятыми, из файла, и был доволен тем, что STDOUT для труб был xargs
и ruby
, например:
cat data.txt | cut -f 16 -d ' ' | grep -o "\d\+" | xargs ruby -e "puts ARGV.join(', ')"
Простой способ соединения строк с пространством на месте с помощью 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
) не является стандартным расширением, а утилита it-self более ориентирована на поток, поэтому она не настолько портативна.
У меня был файл журнала, в котором некоторые данные были разбиты на несколько строк. Когда это произошло, последним символом первой строки была точка с запятой (;). Я присоединился к этим строкам, используя следующие команды:
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
Результатом является файл, в котором строки, которые были разделены в файле журнала, были одной строкой в моем новом файле.
Отвечаю:
awk '{printf "%s", ","$0}' foo.txt
printf
достаточно. Нам не нужно -F"\n"
менять разделитель полей.