Подтвердить что ты не робот

Запретить grep возвращать ошибку, если вход не соответствует

Я хочу написать в bash script фрагмент кода, который проверяет, запущена ли программа. У меня есть следующее для поиска, работает ли бар

 foo=`ps -ef | grep bar | grep -v grep`

 grep -v grep

состоит в том, чтобы убедиться, что "grep bar" не учитывается в результатах ps

Когда бар не работает, foo правильно пуст. Но моя проблема заключается в том, что script имеет

 set -e

который является флагом для завершения script, если какая-либо команда возвращает ошибку. Оказывается, когда бар не работает, "grep -v grep" не соответствует ни с чем, и grep возвращает ошибку. Я попытался использовать -q или -s, но безрезультатно.

Есть ли какое-либо решение? спасибо

4b9b3361

Ответ 1

Конечно:

ps -ef | grep bar | { grep -v grep || true; }

Или даже:

ps -ef | grep bar | grep -v grep | cat

Ответ 2

Хорошим трюком, чтобы избежать grep -v grep, является следующее:

ps -ef | grep '[b]ar'

Это регулярное выражение соответствует строке "bar". Однако в выводе ps строка "bar" не появляется с процессом grep.


За несколько дней до того, как я узнал о pgrep, я написал эту функцию для автоматизации приведенной выше команды:

psg () { 
    local -a patterns=()
    (( $# == 0 )) && set -- $USER
    for arg do
        patterns+=("-e" "[${arg:0:1}]${arg:1}")
    done
    ps -ef | grep "${patterns[@]}"
}

Тогда

psg foo bar

превращается в

ps -ef | grep -e '[f]oo' -e '[b]ar'

Ответ 3

Зачем спрашивать ps, чтобы предоставить массивный объем вывода -ef, если вы собираетесь выбросить 99%? ps и особенно версия GNU - это швейцарский армейский нож удобной функциональности. Попробуйте следующее:

ps -C bar -o pid= 1>/dev/null

Я указываю -o pid= здесь только потому, что, но на самом деле это бессмысленно, так как мы все равно удаляем все stdout. Было бы полезно, если бы вы хотели знать фактический текущий PID.

ps автоматически вернется с ненулевым статусом, если -C не соответствует ничему и с нулем, если он соответствует. Поэтому вы можете просто сказать это

ps -C bar 1>/dev/null && echo bar running || echo bar not running

или

if ps -C bar 1>/dev/null ; then
    echo bar running
else
    echo bar not running
fi

Разве это не проще? Нет необходимости в grep, а не дважды или даже один раз.

Ответ 4

Короткий ответ

Написать

ps -ef | grep bar | { grep -v grep || test $? = 1; }

если вы используете set -e.

Если вы используете pipefail bash pipefail (set -o pipefail), не забудьте применить обработку исключений (||test) к каждому grep в конвейере:

ps -ef | { grep bar || test $? = 1; } | { grep -v grep || test $? = 1; }

В сценариях оболочки я предлагаю вам использовать служебную функцию catch-1-grep (c1grep):

c1grep() { grep "[email protected]" || test $? = 1; }

Разъяснения

Состояние выхода grep: 0, 1 или 2: [1]

  • 0 означает, что линия выбрана
  • 1 означает, что ни одна строка не была выбрана
  • 2 означает, что произошла ошибка

grep может также вернуть другие коды, если он был прерван сигналом (например, 130 для SIGINT).

Поскольку мы хотим игнорировать только состояние выхода 1, мы используем test для подавления этого определенного состояния выхода.

  • Если grep возвращает 0, test не запускается.
  • Если grep возвращает 1, test выполняется и возвращает 0.
  • Если grep возвращает любое другое значение, test выполняется и возвращает 1.

В последнем случае сценарий немедленно завершится из-за set -e или set -o pipefail. Однако, если вас не волнуют ошибки grep, вы можете написать

ps -ef | grep bar | { grep -v grep || true; }

как предложено Шоном.


[дополнительное] использование в скриптах оболочки

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

# "catch exit status 1" grep wrapper
c1grep() { grep "[email protected]" || test $? = 1; }

Таким образом, ваша труба снова станет короткой и простой, не теряя функций set -e и set -o pipefail:

ps -ef | c1grep bar | c1grep -v grep

FYI:

  • Я назвал его c1grep чтобы подчеркнуть, что он просто c1grep состояние выхода 1, ничего больше.
  • Я мог бы вместо этого вызвать функцию grep (grep() { env grep "[email protected]"...; }), но я предпочитаю менее запутанное и более явное имя c1grep.

[1] grep manpage

Ответ 5

foo=`ps -ef | grep bar | grep -v grep` || true

Ответ 6

Попробуйте сделать так:

пс auxw | grep -v grep | кошка

cat всегда возвращает 0 и игнорирует код выхода grep