Як передавати вихід з одного процесу на інший, але виконувати лише якщо перший має вихід?


23

Як я можу переписати цю команду лише на електронну пошту, якщо є вихід з mailq | grep?

mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email

Це можливо навіть на одній лінії?

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


Відповіді:


19

Я думаю, що вам доведеться використовувати тимчасовий файл для цієї операції, щоб ви могли використовувати &&оператора лише для запуску команди пошти, якщо grep повернув статус виходу, який говорить про те, що він відповідає таким:

TMPFILE=`mktemp /tmp/mailqgrep.XXXXXX`; mailq | egrep 'rejected|refused' -A5 -B5 > "$TMPFILE" && mail -s 'dd' email@email < "$TMPFILE"; rm "$TMPFILE"

Якщо ви не заперечуєте, щоб тимчасовий файл десь стирчав і ви можете використовувати для нього статичну назву, ви можете пропустити спеціальний матеріал про іменування та видалення:

 mailq | egrep 'rejected|refused' -A5 -B5 > /tmp/mailqgrep && mail -s 'dd' email@email < /tmp/mailqgrep

Редагувати: Побачивши відповідь glenn, я пограв ще з цим і, мабуть, призначив змінну за допомогою $()синтаксису, повертає код виходу команди, тож ви можете пропустити тест, який він використовував для довжини рядка, і використовувати його замість цього. Ось це все в одній команді:

data=$(mailq | egrep 'rejected|refused' -A 5 -B 5) && mail -s 'dd' email@email <<< "$data"

Правка 2: Побачивши відповідь Саймона, я перевірив свою mailпрограму. Він не веде себе так, як він описує за замовчуванням, але має для цього варіант. На чоловіковій сторінці:

-EЯкщо вихідне повідомлення не містить жодного тексту у своїй першій чи єдиній частині повідомлення, не надсилайте його, а відкидайте його мовчки, ефективно встановлюючи змінну skipemptybody при запуску програми. Це корисно для надсилання повідомлень із скриптів, запущених cron (8).

Зробити це можливим:

mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -E -s 'dd' email@email

1
сила співпраці !!
Гленн Джекман

3
Я б припустив, що цю відповідь можна покращити, перемістивши найкраще рішення вгору.
Марк Бут

@Wildcard Це редагування було непотрібним, враховуючи вхідні параметри mktemp, не збирається повертати те, що потребує цитування.
Калеб

2
Я знаю. Ви один з небагатьох , хто потрудився зрозуміти , що котирування є іноді необхідно (і опускає них навмисно). Однак за замовчуванням має бути цитування, якщо ви прямо не хочете закликати glob(split(var)). Тут вам не потрібно розбиття слів або розширення глобальних файлів, тому не вимагайте їх. Також нам потрібно показати правильний шлях на цьому сайті .
Wildcard

@Wildcard Досить справедливо. Я, як правило, бігаю zshі насправді не отримую глобулювання або розбиття слів у таких випадках, якщо я не прошу їх, але заради відповідей тут і не знаючи цільового середовища, котируючого принципу, це добре.
Калеб

11

Утиліта програма ifne існує прямо для цієї мети: запустити команду, якщо стандартний вхід не порожній.

mailq | egrep 'rejected|refused' -A 5 -B 5 | ifne mail -s 'dd' email@email

Команда ifne є частиною пакету moreutils, який називається "зростаючою колекцією інструментів Unix, яку ніхто не думав писати давно, коли Unix був молодий".


8

Ви можете зберегти результат у змінній, а потім викликати поштову команду, якщо довжина рядка не дорівнює нулю.

data=$(mailq | egrep 'rejected|refused' -A 5 -B 5)
[[ -n "$data" ]] && mail -s 'dd' email@email <<< "$data"

Для одного рядка з'єднайте дві команди двокрапкою.


1
Реквізити для використання змінної замість файлу temp. Це змусило мене замислитися над тим, куди йде вихідний код із команди, з якою ви виконували призначення змінної, і, мабуть, це передається! Дивіться мою оновлену відповідь .
Калеб

7

Використовуйте mailз -Eопцією. У моєму Mac, MAIL (1) говорить, що -Eпрапор не надсилатиме електронну пошту із порожнім корпусом.

-E Не надсилайте повідомлення з порожнім тілом. Це корисно для помилок у конфігурації помилок із сценаріїв cron (8).

На моєму Mac я провів наступний тест. Зауважте, що файл file_does_existіснує, але файл file_does__not_existне існує.

Це надсилає мені електронний лист:

$ ls file_does_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' stefan@example.org

Це не так. Зауважте, що команда ls file_does_not_exist | egrep ...не дає жодного результату.

$ ls file_does_not_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' stefan@example.org
ls: file_does_not_exist: No such file or directory

Калеб побив тебе до цього.
Жил "ТАК - перестань бути злим"

1
Він бив мене лише за 4,75 години :). Я пропустив цю деталь у його тривалій відповіді.
Стефан Ласєвський

5

У цьому конкретному випадку, якщо ваш варіант mailпідтримує-E , просто використовуйте його. У загальному випадку ви можете спробувати прочитати один символ; якщо така є, запустіть команду після обробки та подайте її з символу з решти файлу.

pipe_if_not_empty () {
  a=$(dd bs=1 count=1 2>/dev/null; echo .)  # read at most one character
  if [ "$a" != "." ]; then                  # if there were two characters,
    { printf %s "${a%.}";                   # then output the first character
      cat; } |                              # and the rest of the input   
    "$@"                                    # into the specified program
  fi
}

mailq | egrep 'rejected|refused' -A 5 -B 5 |
pipe_if_not_empty mail -s 'dd' email@email

Зверніть увагу на корисне використання cat. Додавання echo .змушує цю функцію працювати, навіть якщо першим символом на вході є новий рядок (пам’ятайте, що $(…)конструкція смужок терміналу newline ).

Якщо у більшості оболонок (нічого іншого, крім zsh, наскільки я знаю), якщо файл починається з нульового символу, цей код вважатиме, що він порожній. Виправлення, що залишається як вправа для читача. (Примітка: використовуйте odв першому субоболочкі і printf. , Щоб надрукувати перші байти) (Рішення: Як перевірити , якщо труба порожня ) Ви можете зіткнутися з тією ж проблемою , якщо файл починається з байтом , який не є допустимим символом в поточному локальний; це легше виправити, запустивши цей код із LC_ALL=C.


+1 для смішного, але можливо корисного в іншому сценарії :) З цікавості, навіщо вводити та перевіряти крапку замість тестування на порожню рядок? Чи не вводить це проблему, якщо введення починається з крапки? Чи можна за допомогою readдопомогти спростити це?
Калеб

@Caleb: Так, я мав би зазначити, що відповідав на питання в заголовку, а не на конкретну ситуацію. Дивіться мою редакцію для пояснення точки. Я не думаю, що ви можете відрізнити порожній перший рядок від порожнього файлу з readв портативному sh (можливо, це можливо в bash, ksh або zsh).
Жил 'ТАК - перестань бути злим'


1

Нещодавно я дізнався про назву команди, ifneяка є частиною moreutilsпакету. Де ви можете використовувати його для вирішення цієї конкретної проблеми.

ifne - запустити команду, якщо стандартний вхід не порожній

приклад зі сторінки man,

EXAMPLE
       find . -name core | ifne mail -s "Core files found" root

0

Ви можете переписати свою команду, test -s /dev/stdinщоб перевірити, чи є вихід з mailq | grepчастини.

- mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email
+ mailq | egrep 'rejected|refused' -A 5 -B 5 | (test -s /dev/stdin && cat) | mail -s 'dd' email@email
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.