“Doğru değilse” nasıl yapılır?


317

Doğru olmadığında echokomutun çalıştırılmasını istiyorum cat /etc/passwd | grep "sysa".

Neyi yanlış yapıyorum?

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

7
!Parantez içinde olmamalı mı ? ie[ ! EXPR ]
acraig5075

7
@ acraig5075 her iki şekilde de geçerlidir, ancak bu ifadede hiç bir test komutuna (parantezlerin ne olduğu) gerek yoktur.
Charles Duffy

Yanıtlar:


455

Deneyin

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

greptruearama hedefini bulursa döner vefalse .

Yani DEĞİL false== true.

if kabuklardaki değerlendirme çok esnek olacak şekilde tasarlanmıştır ve çoğu zaman komut zincirleri gerektirmez (yazdığınız gibi).

Ayrıca, kodunuza olduğu gibi bakarak, $( ... )cmd ikame formunu kullanımınız övülmelidir, ancak süreçten ne çıktığını düşünün. Deneyin echo $(cat /etc/passwd | grep "sysa")ne demek istediğimi görmek için. -cGrep (say) seçeneğini kullanarak grep ve daha sonra if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thenhangi çalışır ama oldukça eski okul yapmak için bunu daha ileri alabilirsiniz .

AMA, en yeni kabuk özelliklerini (aritmetik değerlendirme) kullanabilirsiniz.

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

bu da size c-lang tabanlı karşılaştırma operatörlerini kullanma avantajı sağlar, ==,<,>,>=,<=,% ve belki de birkaçını .

Bu durumda, Orwellophile tarafından yapılan bir yorumda, aritmetik değerlendirme daha da ayrılabilir, örneğin

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

VEYA

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

Son olarak, adlı bir ödül var Useless Use of Cat (UUOC). :-) Bazı insanlar yukarı ve aşağı atlayacak ve gothca ağlayacak! Sadece söyleyeceğimgrep bunun cmd satırında bir dosya adı alabileceğini neden gerekmediğinde neden ekstra süreçleri ve boru yapılarını çağırıyorsunuz? ;-)

Umarım bu yardımcı olur.


1
Gerçekten çok aptalca, cevabımdan çok daha zor (soru) [ stackoverflow.com/a/30400327/912236] grep "^$user:" /etc/passwd , / etc / passwd'yi yanlışlıkla aramanın daha doğru yolu olurdu - grep -vnerede -v isterseniz aramayı tersine çevirir karışıklık önlemek için ||
Orwellophile

1
Evet, bir problemi en verimli şekilde çözüyoruz ve sonra belirli bir soruyu cevaplıyoruz. Bu soruya cevap vermeye çalıştım. Fikirleriniz için teşekkürler. Hepinize iyi şanslar.
shellter

1
cevaplarınızı seçmemek, oldukça keyif almak. Ben sadece ben kullanıcı adı üzerinde düzgün sınırlı bir kontrol atmak istiyorum, başka OP gerçekten "sys" veya somesuch arama yaparsa, o oldukça sürpriz alırsınız. yol için bir tane daha? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile

1
Harika! Bazı nedenlerden dolayı "! Grep -qs ..." / proc / mounts ile çalışmadı ve Raspbian 4.9 çekirdeğine düzenli olarak bırakılan bir USB diskin takılı olup olmadığını bulmaya çalışıyordu. Bu işi mükemmel yaptı!
DocWeird

33

Bence basitleştirilebilir:

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

veya tek bir komut satırında

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


4
Güzel, ama ben Bay shellter cevabını tercih ediyorum çünkü "kendi kendini belgeledi", programcının niyeti daha "okunabilir".
0zkr PM

1
Bu sürümü beğendim. Üzerine baskı 1>&2yapmak için ekleme yapmaya ne dersiniz ? echostderr
Julien

2
@ 0zkrPM Ancak shellter sürümü Bourne kabuğunda çalışmıyor. Sen alacak!: not found
ceving

1
'grepBu şekilde kullanırken çıkış yeniden yönlendirmesinden kaçının . -qçıktıyı bastırır.
tbc0

8

Neyi yanlış yapıyorum?

$(...)çıkış durumunu değil değeri tutar , bu yüzden bu yaklaşım yanlıştır. Ancak, bu özel durumda, gerçekten işe yarıyor çünkü sysatest ifadesinin gerçekleşmesini sağlayacak yazdırılacak. Ancak, komut if ! [ $(true) ]; then echo false; fiher zaman yazdırılır falseçünkü truekomut stdout'a hiçbir şey yazmaz (çıkış kodu 0 olmasına rağmen). Bu yüzden yeniden ifade edilmesi gerekiyor if ! grep ...; then.

Bir alternatif olabilir cat /etc/passwd | grep "sysa" || echo error. Düzenleme: Alex belirttiği gibi, kedi burada işe yaramaz : grep "sysa" /etc/passwd || echo error.

Diğer cevapları oldukça kafa karıştırıcı buldum, umarım bu birisine yardımcı olur.


1

Onu destekleyen Unix sistemlerinde (macOS değil):

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

Bunun avantajı, kullanımda olabilecek herhangi bir dizin hizmetini (YP / NIS veya LDAP vb.) Ve yerel parola veritabanı dosyasını sorgulayabilmesidir.


Sorun, grep -q "$username" /etc/passwdböyle bir kullanıcı olmadığında yanlış bir pozitif vereceği, ancak desenle eşleşen başka bir şeyin olması. Dosyada başka bir yerde kısmi veya tam eşleşme varsa bu olabilir.

Örneğin passwd, dosyamda şöyle bir satır var:

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

Bu gibi şeylere geçerli bir maç provoke olur carave enocsistemimde böyle kullanıcılar bulunmasına rağmen, vb.

Bir grepçözümün doğru olması için, çözümün doğru şekilde ayrıştırılması gerekir./etc/passwd dosyayı :

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

... ya da :sınırlandırılmış alanların ilkine karşı yapılan benzer bir test .


@SDsolar Kodunuz büyük olasılıkla bashbu durumda yürütülmez .
Kusalananda

1

Örnek bir cevap:

Veri kaydedicilerin çevrimiçi olduğundan emin olmak için bir cronkomut dosyası her 15 dakikada bir şöyle görünür:

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

... montajda görebileceğiniz her veri kaydedici için http://www.SDsolarBlog.com/montage adresini ziyaret edin.


FYI, &>/dev/nullkomutları kullanarak hatalar dahil tüm çıktıları/dev/null

(Şartlı da gerektirir exit statusve pingkomut)

Ayrıca FYI, cronişlerin bir komut dosyasında rootkullanılmasına gerek olmadığı için çalıştığını unutmayın .sudo pingcron

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.