Проверка, содержит ли вывод команды определенную строку в сценарии оболочки

117

Я пишу сценарий оболочки и пытаюсь проверить, содержит ли вывод команды определенную строку. Я думаю, мне, вероятно, придется использовать grep, но я не знаю, как это сделать. Кто-нибудь знает?

user1118764
источник
Должна ли команда продолжать работу после генерации искомой выходной строки или ее можно сразу закрыть в это время? (В этом отношении ваши два ответа различаются семантикой).
Чарльз Даффи,

Ответы:

97

Проверьте возвращаемое значение grep:

./somecommand | grep 'string' &> /dev/null
if [ $? == 0 ]; then
   echo "matched"
fi

что идиоматически делается так:

if ./somecommand | grep -q 'string'; then
   echo "matched"
fi

а также:

./somecommand | grep -q 'string' && echo 'matched'
Perreal
источник
2
Этот код не работает со всеми оболочками POSIX: стандарт POSIX требует только =оператора сравнения, но не ==; см. pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
Чарльз Даффи,
4
Кроме того, grep 'string' &>/dev/nullон несовместим с POSIX и намного медленнее выполняется (если stringпоявляется в начале длинного выходного потока), чем grep -q string. [Предостережение, если вы хотите быть уверенным, что somecommandпродолжает работать даже после отправки string, и в этом случае использование grep -q- путем закрытия его стандартного ввода и выхода после того, как будет обнаружен первый экземпляр string- может быть контрпродуктивным]. (Re: «несовместимо с POSIX» &>- это расширение - см. Pubs.opengroup.org/onlinepubs/009695399/utilities/…, где описывается поддержка перенаправления, предписанная POSIX).
Чарльз Даффи
Помогло бы, если бы было объяснено, почему это работает / что делает каждый параметр, чтобы способствовать полному пониманию синтаксиса
redfox05
159

Тестирование $?- это антипаттерн

if ./somecommand | grep -q 'string'; then
  echo "matched"
fi
мат
источник
Если случайно вы хотите проверить только фиксированную строку, добавьте параметры F и x : grep -Fxq F означает фиксированный (не интерпретируемый), а x для всей строки
Erdal G.
4
Почему тестирование $?антипаттерна?
Виталий Зданевич
1
@VitalyZdanevich Я полагаю, потому что он не устойчив к параллелизму.
Конрад Райх
@VitalyZdanevich, например, тестирование $?не устанавливает предыдущие команды как "проверенные" для целей set -eили ERRловушки, поэтому ваша программа может выйти в тех случаях, когда вы хотите, чтобы она просто вернулась по намеренно ложному пути позже. С другой стороны, $?глобальное состояние изменчиво - его значение легко случайно выбросить. Например, если вы добавите в журнал строку вроде echo "Exit status is $?", новое значение в $?станет статусом выхода echo.
Чарльз Даффи,
6

Другой вариант - проверить соответствие регулярного выражения в выводе команды.

Например:

[[ "$(./somecommand)" =~ "sub string" ]] && echo "Output includes 'sub string'"
Ноам Манос
источник
1

Чистый сценарий условной оболочки if / else:

if ./somecommand | grep -q 'some_string'; then
  echo "exists"
else
  echo "doesn't exist"
fi
Эхсан Баркхордар
источник