Как сделать «если не истинное состояние»?

317

Я хотел бы выполнить echoкоманду, когда cat /etc/passwd | grep "sysa"это не так.

Что я делаю не так?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi
Сандра Шлихтинг
источник
7
Не должно !быть внутри скобок? т.е.[ ! EXPR ]
acraig5075
7
@ acraig5075 это так или иначе, но в этом утверждении вообще нет необходимости в тестовой команде (каковы скобки).
Чарльз Даффи

Ответы:

455

пытаться

if ! grep -q sysa /etc/passwd ; then

grepвозвращает, trueесли находит цель поиска, и falseесли нет.

Так что НЕ false== true.

if Оценка в оболочках разработана так, чтобы быть очень гибкой, и много раз не требует цепочек команд (как вы написали).

Кроме того, глядя на ваш код как есть, $( ... )следует приветствовать использование вами формы подстановки cmd, но подумайте о том, что выходит из процесса. Попробуйте echo $(cat /etc/passwd | grep "sysa")понять, что я имею в виду. Вы можете пойти дальше, используя -cопцию (count) для grep, а затем выполнить то, if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thenчто работает, но это довольно старая школа.

НО, вы можете использовать новейшие функции оболочки (арифметическая оценка), такие как

if ! (( $(grep -c "sysa" /etc/passwd) == 0 )) ; then ...`

что также дает вам преимущество использования операторов сравнения на основе c-lang ==,<,>,>=,<=,%и, возможно, нескольких других.

В этом случае, согласно комментарию Orwellophile, арифметическая оценка может быть урезана еще дальше, например,

if ! (( $(grep -c "sysa" /etc/passwd) )) ; then ....

ИЛИ

if (( ! $(grep -c "sysa" /etc/passwd) )) ; then ....

Наконец, есть награда под названием Useless Use of Cat (UUOC). :-) Некоторые люди будут прыгать вверх и вниз и плакать Gothca! Я просто скажу, что grepможет взять имя файла в его cmd-строке, так зачем вызывать дополнительные процессы и конвейерные конструкции, когда это не нужно? ;-)

Надеюсь, это поможет.

shellter
источник
1
На самом деле все довольно глупо, поскольку мой ответ на гораздо более сложный вопрос ( stackoverflow.com/a/30400327/912236) grep "^$user:" /etc/passwd был бы более правильным способом случайного поиска в / etc / passwd - grep -vгде -v инвертирует поиск, если вы хотите чтобы избежать беспорядка ||
Орвеллофил
1
да, есть решение проблемы наиболее эффективно, а затем ответ на конкретный вопрос. Я пытался ответить на конкретный вопрос. Спасибо за ваши идеи. Всем удачи.
Оболочка
1
не ковыряясь в своих ответах, вполне им понравился. я только что добавил бы правильно ограниченную проверку имени пользователя, иначе, если ОП действительно выполняет поиск по "sys" или что-то подобное, он получит довольно неожиданный результат. еще один для дороги? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Орвеллофил
1
Большой! По какой-то причине reqular "! Grep -qs ..." не работает с / proc / mounts и пытается выяснить, был ли регулярно сбрасываемый USB-диск установлен на ядре Raspbian 4.9. Этот сделал работу отлично!
DocWeird
33

Я думаю, что это может быть упрощено в:

grep sysa /etc/passwd || {
    echo "ERROR - The user sysa could not be looked up"
    exit 2
}

или в одной командной строке

$ grep sysa /etc/passwd || { echo "ERROR - The user sysa could not be looked up"; exit 2; }

Rony
источник
4
Хорошо, но я предпочитаю ответ Mr. shellter, потому что он «самодокументирован», более «читабелен» для программиста.
0zkr PM
1
Мне нравится эта версия. Как насчет добавления 1>&2в конце вашего echoдля печати stderr?
Жюльен
2
@ 0zkrPM Но версия оболочки не работает в оболочке Bourne. Вы получите!: not found
ceving
1
Избегайте перенаправления вывода при использовании, 'grepкак это. -qподавляет вывод.
tbc0
8

Что я делаю не так?

$(...)содержит значение , а не статус выхода, поэтому этот подход неверен. Тем не менее, в этом конкретном случае это действительно работает, потому что sysaбудет напечатано, что делает утверждение теста. Тем не менее, if ! [ $(true) ]; then echo false; fiвсегда будет печатать, falseпотому что trueкоманда ничего не записывает в стандартный вывод (даже если код выхода равен 0). Вот почему это нужно перефразировать if ! grep ...; then.

Альтернатива была бы cat /etc/passwd | grep "sysa" || echo error. Изменить: Как Алекс указал, кот бесполезно здесь : grep "sysa" /etc/passwd || echo error.

Нашли другие ответы довольно запутанно, надеюсь, это кому-нибудь поможет.

phil294
источник
1

В Unix-системах, которые его поддерживают (кажется, не в MacOS):

if getent passwd "$username" >/dev/null; then
    printf 'User %s exists\n' "$username"
else
    printf 'User %s does not exist\n' "$username"
fi 

Преимущество этого заключается в том, что он запрашивает любую службу каталогов, которая может использоваться (YP / NIS или LDAP и т. Д.), И файл локальной базы паролей.


Проблема в grep -q "$username" /etc/passwdтом, что он даст ложное срабатывание, когда такого пользователя нет, но что-то еще соответствует шаблону. Это может произойти, если в файле есть частичное или точное совпадение.

Например, в моем passwdфайле есть строка

build:*:21:21:base and xenocara build:/var/empty:/bin/ksh

Это может спровоцировать правильное совпадение таких вещей, как caraи enocт. Д., Даже если в моей системе таких пользователей нет.

Чтобы grepрешение было правильным, вам нужно правильно проанализировать /etc/passwdфайл:

if cut -d ':' -f 1 /etc/passwd | grep -qxF "$username"; then
    # found
else
    # not found
fi

... или любой другой подобный тест по первому из :полей -delimited.

Kusalananda
источник
@Sdsolar Ваш код, вероятно, не выполняется bashв этом случае.
Кусалананда
1

Вот ответ в качестве примера:

Чтобы убедиться, что регистраторы данных подключены, cronкаждые 15 минут запускается скрипт, который выглядит следующим образом:

#!/bin/bash
#
if ! ping -c 1 SOLAR &>/dev/null
then
  echo "SUBJECT:  SOLAR is not responding to ping" | ssmtp abc@def.com
  echo "SOLAR is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "SOLAR is up"
fi
#
if ! ping -c 1 OUTSIDE &>/dev/null
then
  echo "SUBJECT:  OUTSIDE is not responding to ping" | ssmtp abc@def.com
  echo "OUTSIDE is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "OUTSIDE is up"
fi
#

... и так далее для каждого регистратора данных, который вы можете увидеть на странице монтажа по адресу http://www.SDsolarBlog.com/montage


К вашему сведению, используя &>/dev/nullперенаправления всех выходных данных команды, включая ошибки, в/dev/null

(Условный требует только exit statusот pingкоманды)

Также, к вашему сведению, обратите внимание, что, поскольку cronзадания выполняются как rootнет необходимости использовать sudo pingв cronскрипте.

SDsolar
источник