Bagaimana cara membuat "jika kondisi tidak benar"?


317

Saya ingin echoperintah dieksekusi ketika cat /etc/passwd | grep "sysa"itu tidak benar.

Apa yang saya lakukan salah?

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

7
Haruskah !tidak ada di dalam kurung? yaitu[ ! EXPR ]
acraig5075

7
@ acraig5075 itu sah baik, tetapi tidak perlu untuk perintah uji (yang adalah tanda kurung) dalam pernyataan ini sama sekali.
Charles Duffy

Jawaban:


455

mencoba

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

grepkembali truejika ia menemukan target pencarian, dan falsejika tidak.

Jadi BUKAN false== true.

if evaluasi dalam shell dirancang untuk menjadi sangat fleksibel, dan seringkali tidak memerlukan rantai perintah (seperti yang telah Anda tulis).

Juga, melihat kode Anda apa adanya, penggunaan Anda atas $( ... )bentuk substitusi cmd harus dipuji, tetapi pikirkan tentang apa yang keluar dari proses. Coba echo $(cat /etc/passwd | grep "sysa")lihat apa yang saya maksud. Anda dapat mengambil lebih jauh dengan menggunakan opsi -c(menghitung) untuk menangkap dan kemudian melakukan if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thenyang bekerja tetapi sekolah yang agak lama.

TETAPI, Anda bisa menggunakan fitur shell terbaru (evaluasi aritmatika) seperti

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

yang juga memberi Anda manfaat menggunakan operator perbandingan berbasis c-lang, ==,<,>,>=,<=,%dan mungkin beberapa lainnya.

Dalam hal ini, per komentar oleh Orwellophile, evaluasi aritmatika dapat dikecilkan lebih jauh, seperti

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

ATAU

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

Akhirnya, ada penghargaan yang disebut Useless Use of Cat (UUOC). :-) Beberapa orang akan melompat-lompat dan menangis gothca! Saya hanya akan mengatakan bahwa grepdapat mengambil nama file pada cmd-line-nya, jadi mengapa meminta proses tambahan dan konstruksi pipa ketika Anda tidak perlu? ;-)

Saya harap ini membantu.


1
Ini semua benar-benar konyol, dari jawaban saya ke (pertanyaan) yang jauh lebih sulit [ stackoverflow.com/a/30400327/912236] grep "^$user:" /etc/passwd akan menjadi cara yang lebih benar untuk mencari / etc / passwd secara kebetulan - di grep -vmana -v membalikkan pencarian jika Anda ingin untuk menghindari kekacauan ||
Orwellophile

1
ya, well ada pemecahan masalah yang paling efisien, dan kemudian ada menjawab pertanyaan spesifik. Saya sudah mencoba menjawab pertanyaan spesifik. Terima kasih atas ide Anda. Semoga beruntung untuk semua.
shellter

1
tidak memilih jawaban Anda, cukup menikmatinya. Saya hanya melalui saya akan melemparkan cek benar dibatasi pada nama pengguna, jika OP benar-benar mencari di "sys" atau semacam itu, dia akan mendapatkan cukup kejutan. satu lagi untuk jalan? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile

1
Bagus! Untuk beberapa alasan, reqular "! Grep -qs ..." tidak berfungsi dengan / proc / mounts dan mencoba mencari tahu apakah USB-disk yang terjatuh secara teratur dipasang pada kernel Raspbian 4.9. Yang ini melakukan pekerjaan dengan sempurna!
DocWeird

33

Saya pikir itu bisa disederhanakan menjadi:

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

atau dalam satu baris perintah

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


4
Bagus, tapi saya lebih suka jawaban Mr. shellter karena "didokumentasikan sendiri", lebih "mudah dibaca" maksud programmer.
0zkr PM

1
Saya suka versi ini. Bagaimana dengan menambahkan 1>&2pada akhir Anda echountuk mencetak stderr?
Julien

2
@ 0zkrPM Tetapi versi shellter tidak berfungsi di Bourne shell. Anda akan mendapatkan!: not found
ceving

1
Hindari pengalihan output saat menggunakan 'grepseperti ini. -qmenekan output.
tbc0

8

Apa yang saya lakukan salah?

$(...)memegang nilai , bukan status keluar, itulah sebabnya pendekatan ini salah. Namun, dalam kasus khusus ini, itu memang berhasil karena sysaakan dicetak yang membuat pernyataan pengujian menjadi kenyataan. Namun, if ! [ $(true) ]; then echo false; fiakan selalu mencetak falsekarena trueperintah tidak menulis apa pun ke stdout (meskipun kode keluarnya 0). Itu sebabnya perlu diulang if ! grep ...; then.

Alternatifnya adalah cat /etc/passwd | grep "sysa" || echo error. Edit: Seperti Alex menunjukkan, kucing tidak berguna di sini : grep "sysa" /etc/passwd || echo error.

Menemukan jawaban lain agak membingungkan, semoga ini membantu seseorang.


1

Pada sistem Unix yang mendukungnya (bukan macOS sepertinya):

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

Ini memiliki keuntungan bahwa ia akan meminta layanan direktori apa pun yang mungkin digunakan (YP / NIS atau LDAP dll.) Dan file basis data kata sandi lokal.


Masalahnya grep -q "$username" /etc/passwdadalah bahwa hal itu akan memberikan false positive ketika tidak ada pengguna seperti itu, tetapi sesuatu yang lain cocok dengan polanya. Ini bisa terjadi jika ada kecocokan sebagian atau tepat di tempat lain dalam file.

Misalnya, dalam passwdfile saya , ada garis yang mengatakan

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

Ini akan memicu kecocokan yang valid pada hal-hal seperti caradan enoclain - lain, meskipun tidak ada pengguna seperti itu di sistem saya.

Agar grepsolusi menjadi benar, Anda perlu mengurai /etc/passwdfile dengan benar:

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

... atau tes serupa lainnya terhadap yang pertama dari :bidang -disunting.


@ SDolar Kode Anda mungkin tidak dieksekusi oleh bashdalam kasus itu.
Kusalananda

1

Inilah jawaban sebagai contoh:

Untuk memastikan data logger online, sebuah cronskrip berjalan setiap 15 menit yang terlihat seperti ini:

#!/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
#

... dan seterusnya untuk setiap data logger yang dapat Anda lihat di montase di http://www.SDsolarBlog.com/montage


FYI, menggunakan &>/dev/nullpengalihan semua output dari perintah, termasuk kesalahan, ke/dev/null

(Bersyarat hanya membutuhkan exit statussatu pingperintah)

Juga FYI, perhatikan bahwa karena cronpekerjaan berjalan karena roottidak perlu digunakan sudo pingdalam cronskrip.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.