Может ли grep вернуть true / false или есть альтернативные методы

130

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

grep ^$1 schemas.txt

Я чувствую, что это должно быть намного легче, чем я делаю это.

Я получаю сообщение об ошибке «слишком много аргументов» if. Я избавился от пробела между ними, grep -qа затем получил ошибку двоичного оператора.

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi
Lauren
источник
1
Потерять [... ]и это сработает. Хотя вы, вероятно, хотите процитировать свою модель:if grep -q "^$1" schemas.txt; then …
Дероберт
решение с одной строкой, использующее функцию «Командная команда» Bash: stackoverflow.com/questions/6550484/…
Тревор Бойд Смит,

Ответы:

186

grepвозвращает другой код завершения, если он обнаружил что-то (ноль) и если он ничего не нашел (не ноль). В ifоператоре нулевой код выхода отображается на «истина», а ненулевой код выхода отображается на ложь. Кроме того, у grep есть -qаргумент, чтобы не выводить сопоставленный текст (а только возвращать код состояния выхода)

Итак, вы можете использовать grep следующим образом:

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

В качестве краткого примечания, когда вы делаете что-то подобное if [ -z "$var" ]…, оказывается, что [на самом деле вы запускаете команду, например, grep. В моей системе это так /usr/bin/[. (Технически, ваша оболочка, вероятно, имеет встроенную функцию, но это оптимизация. Она ведет себя так, как если бы она была командой). Он работает так же, [возвращает нулевой код выхода для true, ненулевой код выхода для false. ( testто же самое, что [и за исключением закрытия ])

derobert
источник
Почему для оператора if не нужны скобки? У меня это работает без, но не понимаю почему. Могу ли я все еще вкладывать его без скоб?
Лорен
@Lauren ты пропустил короткую заметку? [не является частью синтаксиса if, это (концептуально) команда, которую вы выполняете, как grep
derobert
2
@Lauren Вы не используете grep внутри [, вы используете один или другой, в зависимости от того, какое условие вы хотите проверить. (Вы можете использовать любую команду внутри if, кстати, если просто проверяет код выхода.)… Ну, я думаю, вы, вероятно, могли бы найти причину использовать grep внутри [, но это был бы довольно сложный сценарий, и его не нормальная вещь, чтобы сделать.
Дероберт
3
К вашему сведению, запустите ls -l /usr/bin/\[и man [увидите, что [эта программа, как и любая другая, просто выглядит как синтаксический элемент - это должно сделать ее более понятной и понятной. (для удобства [также есть встроенные в bash, dash и другие - но это все-таки команда). также попробуйте type -all [в bash.
КАС
1
@AlexanderCska, если вы хотите, чтобы grep печатал совпавшие строки (например, куда-то их направлял), то опустите -qопцию, которая говорит, что grep будет тихим (не печатать совпавшие строки).
Дероберт
48

Другим простым способом является использование grep -c.

Выводит (не возвращает в качестве кода выхода) количество строк, соответствующих шаблону, поэтому 0, если совпадения нет, или 1 или более, если совпадение.

Итак, если вы хотите проверить, что шаблон соответствует 3 или более раз, вы должны сделать:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...
amigal
источник
17
Точнее, это будет выход 1 , если найден только один раз. Для вывода 1 независимо от количества найденных совпадений используйте grep -cim1вместо этого.
manatwork
Этот метод также можно использовать для различения ошибок grep и grep «шаблон найден 0 раз». (хотя не с точным оператором if, я думаю, что переменная требуется)
Эван Бенн
3

Я знаю, что опоздал на это, но мне нравится эта короткая версия:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt
Денис Пицалис
источник
0

Если мы хотим поймать первое слово файла, нам нужно добавить add -zwв grep

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

Без -zмы получаем первое слово строки. Без -wмы получим частичные слова.

JJoao
источник
-2

Если вы хотите использовать его в квадратных скобках, вы можете выполнить ниже

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

Эта логика работает для всех команд, просто поместите ваши команды в кавычки (кнопка над вкладкой или внизу кнопки Esc или слева от кнопки 1)

k_vishwanath
источник
1
Вам необходимо заключить в кавычки `grep -q PATTERN file.txt`, в противном случае применяется оператор split + glob, что может вызвать проблемы для любого вывода, содержащего символы $IFSили символы подстановки. В более общем случае, [ "`cmd`" ]возвращает значение true, если cmdвыводит по крайней мере одну непустую строку на стандартный вывод (с потенциальными проблемами, если выводит байты NUL). Это означает, что оболочка должна будет хранить весь вывод в памяти и ждать его завершения. Использование if cmd | grep -q .вместо этого может быть предпочтительным в этом отношении.
Стефан Шазелас
Эта команда не будет иметь никакого смысла вообще. Назначение -qпереключателя - подавить grep выходной сигнал. Вы говорите: проверьте наличие PATTERN в файле file.txt, отключите все выходные данные, затем установите статус возврата в соответствии с тем, был ли найден PATTERN. Затем проигнорируйте возвращаемый статус, возьмите выходные данные команды (которые мы вынудили оставить пустыми), примените разделение слов и расширение глобуса файла (не приводя ни к каким аргументам вообще), затем выполните команду [(aka test) с ровно одним аргументом, а именно , ]-, а затем, поскольку это приведет к ошибке, эхо "не найден". @ StéphaneChazelas, я что-то пропустил?
Уайлдкарт
1
@Wildcard, ты прав, я, видимо, упустил из виду -q. Этот комментарий имел бы смысл [ `grep PATTERN file.txt ` ], но, как намекает в комментарии, [ "`grep -n PATTERN file.txt`" ]было бы лучше, если бы PATTERN мог соответствовать только пустым строкам. Хотя здесь, конечно, это if grep -q PATTERN file.txtвы хотите.
Стефан Шазелас