Если у меня есть какие-то входные данные, лучше ли отфильтровать данные перед выполнением awk
действия или мне следует выполнить всю фильтрацию заранее awk
?
Например, даны следующие входные данные:
$ echo "foo\nbar\nbaz"
foo
bar
baz
Стоит ли мне бежать:
$ echo "foo\nbar\nbaz" | sed 1q | awk '{ print $0 " cats" }'
foo cats
Или:
$ echo "foo\nbar\nbaz" | awk 'NR == 1 { print $0 " cats" }'
foo cats
- Почему мне следует использовать какой-либо из них?
- Стоит ли использовать другой инструмент?
- Какие факторы следует учитывать?
- Как я могу проверить эти факторы?
решение1
В данном конкретном случае второй вариант является лучшим.
В общем, эффективнее минимизировать количество утилит в конвейере. Лучше не разветвлять (не запускать) ненужные процессы (как в вашем первом примере с ненужным sed
процессом). В Интернете несложно найти примеры жалоб набесполезное использование кошки.
В большинстве современных Unix-подобных систем * разветвление выполняется достаточно эффективно, но зависит от размера запускаемого процесса, например, запуск perl
или python
будет намного медленнее, чем sed
или awk
.
Для однократных команд это не имеет большого значения, но если ваш конвейер находится внутри цикла и запускается много раз, удаление ненужного процесса из вашего конвейера может значительно ускорить общее время выполнения.
Конкретные вопросы
Почему мне следует использовать какой-либо из них?
Если вы лучше знакомы с синтаксисом одного из них, возможно, для удобства чтения кода (и поддержки) лучше использовать тот инструмент/язык, с которым вы лучше всего знакомы.
Стоит ли использовать другой инструмент?
В данном конкретном случае я бы так не думал. Оба awk
и sed
являются подходящими инструментами для такого рода работы.
Какие факторы следует учитывать?
Если вам необходимо обрабатывать несколько файлов (например, в цикле), то скорость/эффективность будут важны.
Если вы время от времени обрабатываете только один большой файл, читаемость кода может быть важнее.
Как я могу проверить эти факторы?
Вы можете профилировать различные версии, используя time
утилиту, доступную как встроенная оболочка Bash, но также и как отдельная исполняемая программа. Например, запуск двух примеров команд показывает, что первый пример занял на .012s больше времени, чем второй.
$ time echo "foo\nbar\nbaz" | sed 1q | awk '{ print $0 " cats" }'
foo\nbar\nbaz cats
real 0m0.056s
user 0m0.000s
sys 0m0.045s
$ time echo "foo\nbar\nbaz" | awk 'NR == 1 { print $0 " cats" }'
foo\nbar\nbaz cats
real 0m0.044s
user 0m0.000s
sys 0m0.031s
Обратите внимание, что на результаты профилирования влияют загрузка системы и другие ограничивающие факторы, поэтому вам придется повторить это множество раз, чтобы получить истинную картину того, какая версия быстрее другой.
* С MS Windows, разветвлениеявляетсяболее затратно, поэтому минимизация количества запускаемых процессов имеет значение при работе в таких средах, как Cygwin.
решение2
Достаточно использоватьawk(илисед) инструмент для таких простых случаев. Сочетание нескольких инструментов было бы слишком сложным и часто излишним:
echo -e "foo\nbar\nbaz" | awk 'NR==1{print $0" cats"}'
Выход:
foo cats
Какие факторы следует учитывать?
Убедитесь, что для необходимой обработки текста требуется сочетание нескольких различных инструментов, в противном случае — используйте возможности одного отдельного инструмента.
Допустим, мне нужно только добавить определенное слово перед первым словом во входной строке — это также легко сделать с помощьюсединструмент:
echo -e "foo\nbar\nbaz" | sed 's/^.*$/& cats/; 1q'
foo cats
echo -e
, e
флаг "включает интерпретацию экранированных обратных косых черт"
В любом случае, это зависит от того, насколько сложен ваш входной текст и насколько сложны ваши правила обработки текста.