Формат вывода xargs

10

Я хотел бы изменить формат вывода xargs

cat k.txt 
1 
2 
3 

И

cat k.txt | xargs 
1 2 3

Однако я хотел бы иметь 1, 2, 3или 1|2|3. Какие-либо предложения?

Авинаш
источник
Это может быть достигнуто с чем - то (не именно это) , как xargs cat -n, но проще , если вы просто обрезать символы новой строки, это может быть достигнуто с echo $(cat), grepили awk(ползание так , как это сделать). xargsне подходят для вашей текущей цели.
41754

Ответы:

18

Ниже приведены дюжина примеров того, как вы можете взять файл, такой как этот:

$ cat k.txt
1
2
3

и преобразовать его в этот формат:

1,2,3

Вы можете использовать эту команду для создания вышеуказанного файла, если вы хотите подыграть:

$ cat <<EOF > k.txt
1
2
3
EOF

Приведенные ниже примеры разбиты на 2 группы. Те, которые "работают" и те, которые "почти" работают. Я оставляю это, потому что часто так же важно видеть, почему что-то не работает, так же как и видеть, почему что-то работает.

Представлено большинство языков сценариев, с которыми я знаком. Некоторые представлены несколько раз, поскольку, как и в известной аббревиатуре, на которую обычно ссылается Perl, TIMTOWTDI .

Примечание: Вы можете поменять запятую ( ,) в примерах ниже , и заменить его любые символы , которые вы хотите, то есть |.

Примеры, которые "работают"

Эти фрагменты кода будут давать желаемый результат.

Команда paste:

$ paste -s -d ',' k.txt 
1,2,3

Команда sed:

$ sed ':a;N;$!ba;s/\n/,/g' k.txt
1,2,3

$ sed ':a;{N;s/\n/,/};ba' k.txt 
1,2,3

Команда perl:

$ perl -00 -p -e 's/\n(?!$)/,/g' k.txt
1,2,3

$ perl -00 -p -e 'chomp;tr/\n/,/' k.txt
1,2,3

Команда awk:

$ awk '{printf"%s%s",c,$0;c=","}' k.txt
1,2,3

$ awk '{printf "%s,",$0}' k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

$ awk -vORS=, 1 k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

$ awk 'BEGIN {RS="dn"}{gsub("\n",",");print $0}' k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

Команда python:

$ python -c "import sys; print sys.stdin.read().replace('\n', ',')[0:-1]" <k.txt
1,2,3

$ python -c "import sys; print sys.stdin.read().replace('\n', ',').rstrip(',')" <k.txt
1,2,3

mapfileВстроенный Bash :

$ mapfile -t a < k.txt; (IFS=','; echo "${a[*]}")
1,2,3

Команда ruby:

$ ruby -00 -pe 'gsub /\n/,",";chop' < k.txt
1,2,3

$ ruby -00 -pe '$_.chomp!"\n";$_.tr!"\n",","' k.txt
1,2,3

Команда php:

$ php -r 'echo strtr(chop(file_get_contents($argv[1])),"\n",",");' k.txt
1,2,3

Предостережения

Большинство приведенных выше примеров будут работать просто отлично. У некоторых есть скрытые проблемы, такие как пример PHP выше. Функция chop()на самом деле является псевдонимом rtrim(), поэтому завершающие пробелы последней строки также будут удалены.

То же самое касается первого примера Ruby и первого примера Python. Проблема заключается в том, как они все используют тип операции, которая по сути "слепо" отсекает конечного персонажа. Это хорошо для примера, который предоставил OP, но следует соблюдать осторожность при использовании этих типов однострочников, чтобы убедиться, что они соответствуют данным, которые они обрабатывают.

пример

Скажем, наш образец файла k.txtвыглядел так:

$ echo -en "1\n2\n3" > k.txt

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

$ python -c "import sys; print sys.stdin.read().replace('\n', ',')[0:-1]" <k.txt
1,2,

Примеры, которые «почти» работают

Это примеры «всегда подружка невесты, а не невеста» . Большинство из них, вероятно, могут быть адаптированы, но когда вы работаете с потенциальным решением проблемы, когда она чувствует себя «вынужденной», это, вероятно, неправильный инструмент для работы!

Команда perl:

$ perl -p -e 's/\n/,/' k.txt
1,2,3,

Команда tr:

$ tr '\n' ','  < k.txt 
1,2,3,

В cat+ echoкоманды:

$ echo $(cat k.txt)
1 2 3

Команда ruby:

$ ruby -pe '$_["\n"]=","' k.txt
1,2,3,

Встроенные Bash while+ read:

$ while read line; do echo -n "$line,"; done < k.txt
1,2,3,
SLM
источник
1
Относительно awkя предпочитаю более короткую альтернативу:awk -vORS=, 1 k.txt
манатворк
Не уверен, что CentOS имеет bash:mapfile -t a < k.txt; (IFS=','; echo "${a[*]}")
Манатворк
не уверен насчет завершающей строки. По моим тестам у тебя perlи у первого awkони тоже есть.
manatwork
Я бы поставил pasteодин наверху. Это именно то, что paste -sздесь. Это стандартная команда, и она будет наиболее эффективной. Все остальные излишни и / или не переносимы или имеют ограничения.
Стефан Шазелас
mapfileотносительно новый, добавлен в bash4.0.
manatwork
4

@slm уже дал хороший ответ, но в качестве вашего вопроса "отформатируйте вывод xargs"

xargs -I{} echo -n "{}|" < test.txt
  • -I опция "заменить строки"
  • {} является заполнителем для выходного текста.
  • Это похоже на использование пары фигурных скобок в «find».

Если вы хотите избавиться от трейлинга, |вы можете использовать его sedдля очистки:

$ xargs -I{} echo -n "{}|" < k.txt  | sed -e 's/|$//'
1|2|3
Рахул Патил
источник
Это добавляет дополнительную трубу после 3. "1 | 2 | 3 |". У меня была та же проблема с циклом while и решением awk.
СЛМ
да, если есть новая линия .. tr, sedи другие также ..
Рахул Патил
2

Это старая ветка, я знаю. ОП спросил с простым кодом, как это. Чтобы приблизить его к оригиналу, у меня есть простое решение.

cat k.txt | xargs
1 2 3

использовать сед

cat k.txt | xargs | sed 's/ /,/g'
1,2,3

или

cat k.txt | xargs | sed 's/ /|/g'
1|2|3

Sed может выглядеть немного странно, но разбито, это имеет большой смысл.

для замены. g 'для global: без этого он будет выполнять только первую замену в каждой новой строке. Поскольку вы используете 'xargs', он отображает их одной строкой. Таким образом, вы получите «1,2 3».

Разделитель используется для разделения. Я использовал символ /. Один интересный трюк: вы можете заменить разделитель большинством других символов, если мы оставим его в том же формате между кавычками. Так что это будет работать также ....

cat k.txt | xargs | sed 's# #,#g'

или

cat k.txt | xargs | sed 'sT T,Tg'

Очевидно, что использование определенных символов в качестве разделителя может привести к путанице, поэтому будьте умны.

Майкл Брюс
источник
0
xargs <k.txt | tr \  \|

Вам не нужно cat- просто передайте входные данные файла и - если не будет дано никакой другой команды - xargsпередадите его формат по умолчанию - который имеет тип с (без интерпретации c-escape/bin/echo с обратной косой чертой) .

xargsудалит пустые места заголовка / хвоста из входного файла и сожмет другие последовательности пробелов вниз до одного пробела. Это означает , что при прохождении файла из trк xargsкак:

tr \\n \| <k.txt | xargs

... печать ...

1|2|3|

... идти другим путем и работать только с аргументами, которые xargsразделяет пробел ....

1|2|3\n

... потому что xargsпечатает последний завершающий символ новой строки (как требуется для текстового файла) , но он не trобрабатывается таким образом.

Обратите внимание, что это (или любое другое решение, предлагаемое здесь) не учитывает xargsцитирование при вводе. xargsбудет выдавать буквально одинарные / двойные / обратные слэш-символы, не являющиеся символом новой строки, при вводе, которые сами могут быть процитированы как

xargs <<\IN
1    2'      3'\'      \'4
IN

1 2      3' '4
mikeserv
источник