วิธีทำ“ ถ้าไม่ใช่สภาพที่แท้จริง”?


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
ควร!จะไม่ภายในวงเล็บ? ie[ ! EXPR ]
acraig5075

7
@ acraig5075 ใช้ได้ทั้งสองทาง แต่ไม่จำเป็นต้องมีคำสั่งทดสอบ (ซึ่งเป็นสิ่งที่วงเล็บ) ในคำสั่งนี้เลย
Charles Duffy

คำตอบ:


454

ลอง

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

grepส่งคืนtrueหากพบเป้าหมายการค้นหาและfalseหากไม่ปรากฏ

ดังนั้นอย่าfalse==true

if การประเมินผลในเชลล์ได้รับการออกแบบให้มีความยืดหยุ่นมากและหลายครั้งไม่จำเป็นต้องมีคำสั่ง (เช่นที่คุณเขียน)

นอกจากนี้เมื่อดูที่รหัสของคุณการใช้$( ... )รูปแบบของการทดแทน cmd จะต้องได้รับการยกย่อง แต่ให้คิดถึงสิ่งที่เกิดขึ้นจากกระบวนการ ลองecho $(cat /etc/passwd | grep "sysa")ดูสิ่งที่ฉันหมายถึง คุณสามารถดำเนินการต่อไปได้โดยใช้-cตัวเลือก (นับ) เพื่อ 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-line ดังนั้นทำไมจึงเรียกใช้กระบวนการพิเศษและการสร้างไพพ์เมื่อคุณไม่ต้องทำ ;-)

ฉันหวังว่านี่จะช่วยได้.


1
มันค่อนข้างโง่จริง ๆ ตั้งแต่คำตอบของฉันไปจนถึงคำถามที่ยากขึ้น [ stackoverflow.com/a/30400327/912236] grep "^$user:" /etc/passwdจะเป็นวิธีที่ถูกต้องมากขึ้นในการค้นหา / etc / passwd โดยบังเอิญ - grep -vที่-vสลับการค้นหาถ้าคุณต้องการ เพื่อหลีกเลี่ยงความยุ่งเหยิงของ ||
Orwellophile

1
ใช่มีการแก้ปัญหาได้อย่างมีประสิทธิภาพมากที่สุดแล้วก็มีการตอบคำถามเฉพาะ ฉันพยายามตอบคำถามเฉพาะ ขอบคุณสำหรับความคิดของคุณ โชคดีทุกคน.
shellter

1
ไม่เลือกคำตอบของคุณ แต่สนุกกับพวกเขา ฉันเพิ่งผ่านฉันจะโยนในการตรวจสอบอย่างถูกต้องเกี่ยวกับชื่อผู้ใช้อื่นถ้า OP จริง ๆ ค้นหา "sys" หรือ somesuch เขาจะได้รับค่อนข้างแปลกใจ อีกหนึ่งทางสำหรับถนน? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile

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


4
ดี แต่ฉันชอบคำตอบของ Mr. shellter เพราะเป็น "self documented" มากกว่า "readable" เจตนาของโปรแกรมเมอร์
0zkr PM

1
ฉันชอบรุ่นนี้ สิ่งที่เกี่ยวกับการเพิ่ม1>&2ในตอนท้ายของechoการพิมพ์ของคุณstderr?
Julien

2
@ 0zkrPM แต่รุ่น shellter ไม่สามารถใช้งานได้ใน Bourne shell คุณจะได้รับ!: not found
ceving

1
หลีกเลี่ยงการเปลี่ยนเส้นทางเอาต์พุตเมื่อใช้ใน'grepลักษณะนี้ -qยับยั้งเอาต์พุต
tbc0

8

ผมทำอะไรผิดหรือเปล่า?

$(...)เก็บค่าไม่ใช่สถานะออกนั่นคือสาเหตุที่วิธีการนี้ผิด อย่างไรก็ตามในกรณีเฉพาะนี้มันใช้งานได้จริงเพราะsysaจะพิมพ์ออกมาซึ่งทำให้ข้อความทดสอบเป็นจริง อย่างไรก็ตามif ! [ $(true) ]; then echo false; fiจะพิมพ์เสมอfalseเพราะtrueคำสั่งไม่ได้เขียนอะไรไปยัง stdout (แม้ว่ารหัสออกเป็น 0) if ! grep ...; thenนั่นคือเหตุผลที่จะต้องมีการซักค้านไป

cat /etc/passwd | grep "sysa" || echo errorทางเลือกที่จะ เมื่ออเล็กซ์ชี้ให้เห็นแมวก็ไม่มีประโยชน์อะไรที่นี่ : grep "sysa" /etc/passwd || echo error.

พบคำตอบอื่น ๆ ที่ค่อนข้างสับสนหวังว่านี้จะช่วยให้ใครบางคน


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

... หรือการทดสอบอื่น ๆ ที่คล้ายคลึงกับ:ฟิลด์แรกของเขตข้อมูลที่ถูก จำกัด


@SDsolar รหัสของคุณอาจไม่ถูกเรียกใช้งานbashในกรณีนั้น
Kusalananda

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


FYI โดยใช้การ&>/dev/nullเปลี่ยนเส้นทางเอาต์พุตทั้งหมดจากคำสั่งรวมถึงข้อผิดพลาดไปยัง/dev/null

(ในเงื่อนไขเท่านั้นต้องexit statusของpingคำสั่ง)

นอกจากนี้ FYI โปรดทราบว่าตั้งแต่cronงานรันเนื่องจากrootไม่จำเป็นต้องใช้sudo pingในcronสคริปต์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.