Команда для додавання рядка до кожного рядка?


36

Шукаєте щось подібне? Якісь ідеї?

cmd | prepend "[ERRORS] "

[ERROR] line1 text
[ERROR] line2 text
[ERROR] line3 text
... etc

Чи є спосіб встановити це для всіх команд у bash function / script?
Олександр Міллс

Відповіді:


39
cmd | while read line; do echo "[ERROR] $line"; done

має перевагу лише у використанні bash вбудованих, тому буде створено / знищено менше процесів, тому це має бути дотиком швидше, ніж awk або sed.

@tzrik зазначає, що це також може зробити гарну функцію баш. Визначивши це як:

function prepend() { while read line; do echo "${1}${line}"; done; }

дозволив би використовуватись так:

cmd | prepend "[ERROR] "

4
Це насправді лише зменшує кількість процесів на одиницю. (Але це може бути швидше, тому що не використовуються регулярні вирази ( sed) або навіть розбиття рядків ( awk).)
grawity

До речі, мені було цікаво про продуктивність, і ось результати мого простого еталону з використанням bash, sed та awk. Натиснувши близько 1000 рядків тексту (dmesg-вихід) у файл FIFO, а потім прочитайте їх так: pastebin.ca/1606844 Схоже, переможець є awk. Будь-які ідеї чому?
Ілля Закреуський

1
будьте обережні, виконуючи такі тести на синхронізацію - спробуйте виконати їх у всіх 6 різних порядках, а потім усереднюйте результати. Різні замовлення на пом'якшення ефектів кеш-блоку та середнє для пом'якшення ефектів переривання фону / планування.
pjz

Це питання позначено "оболонка", а не "баш".
fiatjaf

1
Досить просто, щоб function prepend() { while read line; do echo "${1}${line}"; done; }
увімкнути

46

Спробуйте це:

cmd | awk '{print "[ERROR] " $0}'

Ура


1
Це має той недолік, що "[ПОМИЛКА]" не може бути змінною, оскільки весь вираз повинен бути в одноцитатах.
користувач1071136

4
awk -vT="[ERROR] " '{ print T $0 }'абоawk -vT="[ERROR]" '{ print T " " $0 }'
Тіно

2
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }'абоT="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }'
Тіно

Ви можете просто вийти з сфери цитат, щоб зменшити значення змінної: cmd | awk '{print "['$V]' " $0}'- це слід оцінювати один раз на старті, так що без накладних витрат.
Роберт

13

З усією належною заслугою до @grawity, я надсилаю його коментар як відповідь, оскільки це здається мені найкращою відповіддю.

sed 's/^/[ERROR] /' cmd

Чому це краще для баш-рішення?
користувач14645

1
Я думаю, це залежить від вашої мети. Якщо ваша мета - просто додати кожен рядок у файлі, це досягає цілі з дуже мало символів, використовуючи дуже знайомий інструмент. Я набагато віддаю перевагу цьому 10-рядковому сценарію bash. awkОдин-лайнер досить хороший, але я думаю , що все більше людей знайомі з sedчим awk. Баш сценарій хороший для того, що він робить, але, здається, він відповідає на питання, яке не було задано.
Ерік Вілсон

Відповідь, яку подав pjz, також є приємною однолінійкою. Це не додаткові програми, процеси та може працювати трохи швидше.
користувач14645

3
sed X cmdчитає cmdі не виконує його. Або cmd | sed 's/^/[ERROR] /'чи sed 's/^/[ERROR] /' <(cmd)або cmd > >(sed 's/^/[ERROR] /'). Але остерігайтеся останнього. Навіть те , що це дозволяє отримати доступ до що повертається значенням cmdв sedпрогонах в фоновому режимі, так що, швидше за все , ви побачите результат після ЦМДА готового. Хоча добре для входу у файл. І зауважте, що, awkймовірно, швидше, ніж sed.
Тіно

Приємно. Ця команда легко псевдонімічна. alias lpad="sed 's/^/ /'". замість ПОМИЛКИ я вставляю 4 провідні пробіли. Тепер для магічного трюку: ls | lpad | pbcopyбуде додано ls-висновок з 4 пробілами, який позначає його як Markdown для коду , це означає, що ви вставляєте буфер обміну ( pbcopy захоплює його на macs) безпосередньо в StackOverflow або будь-який інший контекст розмітки. Чи не вдалося AWK відповідь (на 1 - й спроби) так що це один виграє. У той час як рішення для читання також може бути псевдонімом, але я вважаю цей sed більш виразним. alias
JL Peyret

8

Я створив сховище GitHub, щоб зробити кілька тестів на швидкість.

Результат:

  • У загальному випадку awkце найшвидше. sedтрохи повільніше і perlне набагато повільніше, ніж sed. Мабуть, усі ці мови є оптимізованими для обробки тексту.
  • У дуже особливих ситуаціях, де домівки домінують, запуск сценарію у вигляді складеного kshсценарію ( shcomp) може заощадити ще більше часу на обробку. На противагу цьому, bashмертво повільно порівняно зі складеними kshсценаріями.
  • Створення статично пов'язаного бінарного файлу для перемоги, awkздається, не варто докладати зусиль.

На противагу цьому pythonмертво повільно, але я не перевіряв складений випадок, оскільки це зазвичай не те, що ви робили б у такому сценарії.

Наступні варіанти тестуються:

while read line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST]" $line; done
while read -r line; do echo "[TEST]" "$line"; done
sed 's/^/[TEST] /'
awk '{ print "[TEST] " $0 }'
awk -vT="[TEST] " '{ print T $0 }'
awk -vT="[TEST]" '{ print T " " $0 }'
awk -vT="[TEST]" 'BEGIN { T=T " "; } { print T $0 }'
T="[TEST] " awk '{ print ENVIRON["T"] $0 }'
T="[TEST]" awk '{ print ENVIRON["T"] " " $0 }'
T="[TEST]" awk 'BEGIN { T=ENVIRON["T"] " " } { print T $0 }'
perl -ne 'print "[TEST] $_"'

Два бінарні варіанти одного з моїх інструментів (однак він не оптимізований для швидкості):

./unbuffered.dynamic -cp'[TEST] ' -q ''
./unbuffered.static -cp'[TEST] ' -q ''

Завантажений Python:

python -uSc 'import sys
for line in sys.stdin: print "[TEST]",line,'

І розблокований Python:

python -uSc 'import sys
while 1:
 line = sys.stdin.readline()
 if not line: break
 print "[TEST]",line,'

awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }'для виведення часової позначки
Тіно,


3

Я хотів рішення, яке обробляло stdout і stderr, тому я написав prepend.shі поставив це на своєму шляху:

#!/bin/bash

prepend_lines(){
  local prepended=$1
  while read line; do
    echo "$prepended" "$line"
  done
}

tag=$1

shift

"$@" > >(prepend_lines "$tag") 2> >(prepend_lines "$tag" 1>&2)

Тепер я можу просто запустити prepend.sh "[ERROR]" cmd ..., щоб додати "[ПОМИЛКУВАННЯ]" до виводу cmd, і ще мати окремі stderr та stdout.


Я спробував такий підхід, але щось із тим, >(що не вдалося вирішити, відбувалося з тими підрозділами. Здавалося, що сценарій завершується, і висновок надходить до терміналу після повернення підказки, який був трохи безладним. Я врешті-решт придумав відповідь тут stackoverflow.com/a/25948606/409638
robert
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.