Стоит ли фильтровать входные данные перед запуском действия awk?

Стоит ли фильтровать входные данные перед запуском действия awk?

Если у меня есть какие-то входные данные, лучше ли отфильтровать данные перед выполнением 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флаг "включает интерпретацию экранированных обратных косых черт"


В любом случае, это зависит от того, насколько сложен ваш входной текст и насколько сложны ваши правила обработки текста.

Связанный контент