Есть ли способ установить это для всех команд в функции / скрипте bash?
Александр Миллс
Ответы:
39
cmd | while read line; do echo "[ERROR] $line"; done
имеет преимущество только использования встроенных команд bash, так что будет создаваться / уничтожаться меньше процессов, поэтому он должен быть на ощупь быстрее, чем awk или sed.
@tzrik указывает, что это может также сделать хорошую функцию bash. Определяя это как:
function prepend() { while read line; do echo "${1}${line}"; done; }
На самом деле это только уменьшает количество процессов на единицу. (Но это может быть быстрее, потому что не используются regexps ( sed) или даже разбиение строк ( awk).)
grawity
Кстати, мне было интересно узнать производительность, и вот результаты моего простого теста с использованием bash, sed и awk. Выкладываем около 1000 строк текста (вывод dmesg) в файл FIFO и затем читаем их следующим образом: pastebin.ca/1606844 Похоже, awk - победитель. Есть идеи почему?
Илья Закреевский
1
будьте осторожны при проведении таких временных тестов - попробуйте выполнить их во всех 6 различных порядках, а затем усредните результаты. Различные порядки для смягчения эффектов блочного кэша и усреднения для смягчения фоновых эффектов прерывания / планирования.
pjz
Этот вопрос помечен как "shell", а не как "bash".
Пятница,
1
Достаточно просто, чтобы обернуть его в функцию:function prepend() { while read line; do echo "${1}${line}"; done; }
Вы можете просто выйти из области видимости кавычек, чтобы разыменовать переменную: cmd | awk '{print "['$V]' " $0}'- это должно быть оценено один раз в начале, так что никаких потерь производительности не будет.
Роберт
13
С уважением к @grawity, я представляю его комментарий в качестве ответа, так как он кажется мне лучшим ответом.
Я полагаю, это зависит от вашей цели. Если ваша цель состоит в простом добавлении каждой строки в файле, это достигается с помощью очень небольшого количества символов с использованием очень знакомого инструмента. Я предпочитаю это сценарию с 10 строками. awkОдин-лайнер достаточно хорош, но я думаю , что все больше людей знакомы с sedчем awk. Сценарий bash хорош для того, что он делает, но кажется, что он отвечает на вопрос, который не был задан.
Эрик Уилсон
Ответ, который представил pjz, также является хорошим однострочником. Это не дополнительные программы, процессы и может работать немного быстрее.
user14645
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 или любой другой контекст уценки. Не удалось получить ответ aliasот awk (с 1-й попытки), поэтому этот выигрывает. Решение while read также может создавать псевдонимы, но я нахожу это sed более выразительным.
В общем случае 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] $_"'
Два бинарных варианта одного из моих инструментов (хотя он не оптимизирован по скорости):
Я попробовал этот подход, но с этими >(оболочками происходило что-то, что я не мог решить. Казалось, что сценарий завершается, и вывод возвращается на терминал после возвращения приглашения, что было немного грязно. В конце концов я пришел с ответом здесь stackoverflow.com/a/25948606/409638
Ответы:
имеет преимущество только использования встроенных команд bash, так что будет создаваться / уничтожаться меньше процессов, поэтому он должен быть на ощупь быстрее, чем awk или sed.
@tzrik указывает, что это может также сделать хорошую функцию bash. Определяя это как:
позволит использовать его как:
источник
sed
) или даже разбиение строк (awk
).)function prepend() { while read line; do echo "${1}${line}"; done; }
Попробуй это:
ура
источник
awk -vT="[ERROR] " '{ print T $0 }'
илиawk -vT="[ERROR]" '{ print T " " $0 }'
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }'
илиT="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }'
cmd | awk '{print "['$V]' " $0}'
- это должно быть оценено один раз в начале, так что никаких потерь производительности не будет.С уважением к @grawity, я представляю его комментарий в качестве ответа, так как он кажется мне лучшим ответом.
источник
awk
Один-лайнер достаточно хорош, но я думаю , что все больше людей знакомы сsed
чемawk
. Сценарий bash хорош для того, что он делает, но кажется, что он отвечает на вопрос, который не был задан.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 или любой другой контекст уценки. Не удалось получить ответalias
от awk (с 1-й попытки), поэтому этот выигрывает. Решение while read также может создавать псевдонимы, но я нахожу это sed более выразительным.Я создал GitHub-репозиторий для тестирования скорости.
Результат:
awk
самый быстрый.sed
немного медленнее иperl
не намного медленнее, чемsed
. По-видимому, все это высоко оптимизированные языки для обработки текста.ksh
скрипта (shcomp
) может сэкономить еще больше времени на обработку. Напротив, онbash
очень медленный по сравнению со скомпилированнымиksh
скриптами.awk
Кажется, создание статически связанного двоичного файла не стоит этих усилий.Напротив, он
python
очень медленный, но я не проверял скомпилированный случай, потому что это обычно не то, что вы бы сделали в таком случае сценариев.Тестируются следующие варианты:
Два бинарных варианта одного из моих инструментов (хотя он не оптимизирован по скорости):
Python буферизован:
И Python небуферизованный:
источник
awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }'
вывести метку времениисточник
sed 's/^/[ERROR] /'
Я хотел решение, которое обрабатывало бы stdout и stderr, поэтому я написал
prepend.sh
и поставил его на моем пути:Теперь я могу просто запустить
prepend.sh "[ERROR]" cmd ...
, чтобы добавить «[ERROR]» к выводуcmd
, и при этом разделить stderr и stdout.источник
>(
оболочками происходило что-то, что я не мог решить. Казалось, что сценарий завершается, и вывод возвращается на терминал после возвращения приглашения, что было немного грязно. В конце концов я пришел с ответом здесь stackoverflow.com/a/25948606/409638