Объедините несколько команд Unix в один выход

9

Мне нужно найти в наших почтовых журналах конкретный адрес электронной почты. Мы сохраняем текущий файл с именем maillog, а также файлы .bz2 за неделю в той же папке. В настоящее время я запускаю следующие команды для поиска файла:

grep person@domain.com maillog
bzgrep person@domain.com *.bz2

Есть ли способ объединить grepи bzgrepкоманды в один выход? Таким образом, я мог бы перенаправить объединенные результаты в одно электронное письмо или в один файл.

Бен МакКормак
источник

Ответы:

24

Другой способ

{ grep ...; bzgrep ...;} >file

&&имеет трудность, bzgrepчто не будет работать, если grepне удалось.

Обратите внимание на обязательный пробел после открывающей фигурной скобки и точку с запятой после последней команды. Кроме того, вы можете использовать синтаксис subshell (круглые скобки вместо фигурных скобок), который не так требователен:

(grep ...; bzgrep ...) >file
geekosaur
источник
+1 за лучший общий подход к этой проблеме. Группировка оболочки - это обычно недостаточно используемая функция.
Фил Холленбек
2
Разве вы не имеете в виду ()вместо {}?
Этеш Чоудхури
На arch linux это работало, ()но не в {}любом случае +1, так как это то, что мне было нужно!
Крис Магнусон
11

bzgrep автоматически по умолчанию использует обычный grep, если файл не сжат в bzip. Таким образом, следующего должно быть достаточно:

bzgrep person@domain.com maillog *bz2 | mail -s "logs yay" someuser@blah

о, конечно же, вот и мое обязательное параллельное решение GNU :

parallel -m bzgrep person@domain.com ::: maillog* *bz2 | mail -s "logs yay" someuser@blah

что может быть намного быстрее, если вы проверяете много файлов.

Фил Холленбек
источник
2

Вот еще один способ сделать это (при условии, что вы используете bash, что, вероятно, и есть):

cat <(bzgrep ...) <(grep ...)

Здесь bash прозрачно передает выходные данные команд bzgrep и grep в cat, как если бы они были файлами (и они вроде находятся под капотом, детали в url внизу).

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

Если вам интересно, вы можете прочитать больше здесь: http://www.tldp.org/LDP/abs/html/process-sub.html

Дрю Блохл
источник
Ах да, канонический ответ на вопрос «как вы различаете результаты двух процессов». Хороший трюк, чтобы знать.
Фил Холленбек
1

На момент написания этой статьи синтаксис принятого ответа был неправильным для большинства, если не для всех оболочек, производных от Борна, в том числе bash. Я предложил правку сверху и принял ответ, чтобы исправить это, но я также был склонен добавить всю эту другую информацию, и это было бы скорее переписать, чем редактировать.

Вы можете использовать составные команды:

{ grep ...; bzgrep ...; } >file

..или подоболочки (обратите внимание на круглые скобки вместо фигурных скобок):

(grep ...; bzgrep ...) >file

..группировать команды. Способ subshell имеет более приятный синтаксис (более простое отсутствие пробелов и позволяет пропустить последнюю точку с запятой), но он либо разветвляет новый процесс, либо «делает вид», выполняя команды в очищенной среде. Оба имеют свои преимущества в зависимости от того, что вы хотите сделать, которые здесь не имеют значения, но их стоит посмотреть, если вы хотите больше владеть оболочкой.

Примечание. С этими приемами вы также можете использовать конвейерную обработку, так что вы можете сделать что-то вроде этого:

{ grep ...; bzgrep ...; } | less

PS если вы не заботитесь о упорядочении матчей в вашей совокупной продукции, вы можете использовать один &между двумя командами, например , так: { grep ... & bzgrep ...; }. Затем две команды выполняются одновременно: grepзапускается и оболочка помещает его в фоновый режим, затем оболочка запускает bzgrep. (Но с этим есть небольшая оговорка: объяснение, включающее перенаправление файлов и буферизацию файлового потока, потенциально может привести к разделению / искажению очень маленькой части строк в выходном файле: увидите ли вы, что это будет зависеть от того grep, как вы , bzgrepи libc stdio.hфункции реализованы. В большинстве реализаций я полагаю, что передача команды перед перенаправлением в файл позволит избежать проблемы, так что вы можете сделать это { foo & bar; } | cat - >fileв качестве обходного пути.)

mtraceur
источник
0

Вы можете связать команды вместе с &&, что позволит вам выполнить каждую команду.

Вы также можете добавить >> textfile.txt в конец каждой команды, чтобы результат попадал в файл, а затем отправлял его по почте.

Майк
источник
2
Как упоминал geekosaur, && не следует использовать здесь, потому что возвращаемое значение grep зависит от того, нашел он что-то или нет. Если вы это сделаете grep ... && bzgrep ..., если у grep нет попаданий, он вернет ошибку и команда остановится. >>Это хорошая идея, хотя, в отличие от этого >, она добавит вывод в конец существующего файла.
DerfK
Правильно, я забыл про условие выхода, препятствующее второй команде.
Майк