web-dev-qa-db-ja.com

「本当でない場合」の作り方

cat /etc/passwd | grep "sysa"が正しくないときにechoコマンドを実行したいのですが。

何がおかしいのですか?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi
260

やってみる

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

grepは、検索対象が見つかった場合はtrueを返し、見つからなかった場合はfalseを返します。

NOT false == trueです。

シェルでのifの評価は非常に柔軟になるように設計されており、(あなたが書いたように)多くの場合コマンドの連鎖を必要としません。

また、コードをそのまま見て、$( ... )形式のcmd-substitutionを使用することをお勧めしますが、プロセスから何が出てくるのかを考えてください。 echo $(cat /etc/passwd | grep "sysa")を試して、私の意味を確認してください。 grepに-c(count)オプションを使用してさらに機能させることもできますが、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 ....

OR

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

最後に、 award Useless Use of Cat (UUOC)と呼ばれています。 :-)何人かの人々が飛び降りてゴスカを泣くでしょう! grepはcmd行でファイル名を取ることができると言いますが、必要ではないのになぜ追加のプロセスやパイプ構造を呼び出すのでしょうか。 ;-)

これが役に立つことを願っています。

384
shellter

これは次のように単純化できると思います。

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; }

30
Rony

何がおかしいのですか?

$(...)は終了ステータスではなく value を保持しているので、このアプローチは間違っています。しかし、この特定のケースでは、sysaが出力されてテスト文が真になるので、実際にはうまくいきます。ただし、falseコマンドは(終了コードが0であっても)stdoutに何も書き込まないため、if ! [ $(true) ]; then echo false; fiは常にtrueを出力します。それがif ! grep ...; thenに言い換える必要がある理由です。

代替手段はcat /etc/passwd | grep "sysa" || echo errorです。編集:アレックスが指摘したように、 catはここでは役に立ちませんgrep "sysa" /etc/passwd || echo error

他の答えがやや紛らわしいと思った、これが誰かに役立つことを願っています。

5
Blauhirn

これは例としての答えです:

データロガーがオンラインであることを確認するために、cronスクリプトが15分ごとに実行されます。

#!/bin/bash
#
if ! ping -c 1 SOLAR &>/dev/null
then
  echo "SUBJECT:  SOLAR is not responding to ping" | ssmtp [email protected]
  echo "SOLAR is not responding to ping" | ssmtp [email protected]
else
  echo "SOLAR is up"
fi
#
if ! ping -c 1 OUTSIDE &>/dev/null
then
  echo "SUBJECT:  OUTSIDE is not responding to ping" | ssmtp [email protected]
  echo "OUTSIDE is not responding to ping" | ssmtp [email protected]
else
  echo "OUTSIDE is up"
fi
#

...各モンタージュの http://www.SDsolarBlog.com/montage で見ることができる各データロガーについて


参考として、&>/dev/nullを使用すると、エラーを含むコマンドからのすべての出力が/dev/nullにリダイレクトされます。

(条件はpingコマンドのexit statusのみを必要とします)

また、cronジョブはrootとして実行されるため、cronスクリプトでSudo pingを使用する必要はありません。

1
SDsolar

それをサポートする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

たとえ私のシステムにそのようなユーザがいなくても、これはcaraenocなどのようなものに対して有効な一致を引き起こすでしょう。

grepソリューションを正しくするには、/etc/passwdファイルを正しく解析する必要があります。

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

...または:で区切られた最初のフィールドに対する同様のテスト。

1
Kusalananda