POSIX-совместимо использовать функцию оболочки в конвейере?

356
Tim Bird

Можно ли использовать функцию оболочки в конвейере?

Скажем, у меня была функция, которая действовала как grep, называется mygrep. Есть ли способ, используя только функции оболочки POSIX, чтобы иметь возможность вызывать mygrepтак:

if ps | mygrep foo ; then echo "process foo is running" fi 

Или трубопровод ограничен только внешними командами?

1
Что мешает тебе попробовать? Kamil Maciorowski 5 лет назад 1
@KamilMaciorowski: Возможно, неопределенность в том, работает ли она из-за того, что она является стандартной функцией POSIX, или из-за того, что она является одним из миллиона расширений ksh / bash / zsh. Когда OP упоминает «используя только ...», лучше всего предположить, «это * должно * работать?» grawity 5 лет назад 1
@ Grawity Разумное предположение, я понимаю вашу точку зрения. Если это так, предоставление результатов собственных тестов в нескольких оболочках было бы хорошим исследовательским усилием. Kamil Maciorowski 5 лет назад 0
@grawity Мой ответ теперь решает эту проблему. Спасибо. Kamil Maciorowski 5 лет назад 0

2 ответа на вопрос

4
Kamil Maciorowski

Да. Смотрите этот документ .

1. Введение

В разделе «Shell and Utilities» в POSIX.1-2017 описываются команды и утилиты, предлагаемые прикладным программам в POSIX-совместимых системах.

От 2.9.2 Трубопроводы :

Конвейер представляет собой последовательность из одной или нескольких команд, разделенных оператором управления '|'.

С 2.9.5 Команда определения функции :

Функция - это пользовательское имя, которое используется как простая команда [...]

Формат команды определения функции следующий:

fname ( ) compound-command [io-redirect ...] 

Из 2.9 Команды оболочки :

Команда является одной из следующих:

  • Простая команда [...]
  • [...]

Так |отделяет команды; команда может быть простой командой; Имя функции используется как простая команда. Ответ на ваш вопрос: да, этот синтаксис

some_command | some_function 

определяется POSIX.


Это довольно просто попробовать (протестировано с shпомощью dashв Debian 9):

mygrep() { grep "$@"; }  if ps | mygrep foo ; then echo "process foo is running" fi  if ps | mygrep ps ; then echo "process ps is running" fi 

( ps | mygrep fooтакже обнаружит процесс foobar, если таковой имеется. Я понимаю, что эта проблема выходит за рамки вашего вопроса, и мы можем ее игнорировать).

В этом примере mygrepэто тривиально. Возвращает статус выхода своей последней (и единственной) команды. При построении функций с более сложной логикой вам может потребоваться специальная встроенная функция returnдля возврата желаемого состояния выхода.

Также обратите внимание, что вывод из grepне подавляется. В каналах можно использовать не только функцию оболочки, но и ее вывод. Пример:

if ps | mygrep ps >/dev/null ; then echo "process ps is running" fi 
заменено комментарием ниже. SE вел себя странно, и, похоже, мой комментарий не был сохранен. Tim Bird 5 лет назад 0
Я смущен, что я не попробовал это сам. Я думал, что обработка stdin будет более сложной, но в ретроспективе кажется очевидным, что он просто «уходит» в функцию (если это так). То, что вы можете перенаправить вывод функции, также очень интересно. Спасибо! Tim Bird 5 лет назад 0
-2
Yurij

Вы должны использовать форму oneliner или упаковать выражение в $ {}. В той форме, которую вы написали как bash-скрипт, это невозможно.

Я не очень понимаю, что вы имеете в виду. Можете ли вы опубликовать пример? рабочий кусок кода? Насколько я знаю, `$ {}` работает с переменными и делает возможными такие вещи, как `echo" $ _suffix "`. Kamil Maciorowski 5 лет назад 1
чуть выше пример mygrep () Yurij 5 лет назад 0

Похожие вопросы