Ответ 1
Конечно:
ps -ef | grep bar | { grep -v grep || true; }
Или даже:
ps -ef | grep bar | grep -v grep | cat
Я хочу написать в 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, но безрезультатно.
Есть ли какое-либо решение? спасибо
Конечно:
ps -ef | grep bar | { grep -v grep || true; }
Или даже:
ps -ef | grep bar | grep -v grep | cat
Хорошим трюком, чтобы избежать 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'
Зачем спрашивать 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, а не дважды или даже один раз.
Написать
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
foo=`ps -ef | grep bar | grep -v grep` || true
Попробуйте сделать так:
пс auxw | grep -v grep | кошка
cat всегда возвращает 0 и игнорирует код выхода grep