ฉันจะออกจากสคริปต์ในคำสั่งแบบมีเงื่อนไขได้อย่างไร


50

ฉันกำลังเขียนสคริปต์ทุบตีที่ฉันต้องการออกหากผู้ใช้ไม่ได้รูท เงื่อนไขทำงานได้ดี แต่สคริปต์ไม่ออก

[[ `id -u` == 0 ]] || (echo "Must be root to run script"; exit)

ฉันลองใช้&&แทนที่จะใช้;แต่ไม่ได้ผล

คำตอบ:


50

คุณสามารถทำเช่นนี้ได้:

[[ $(id -u) -eq 0 ]] || { echo >&2 "Must be root to run script"; exit 1; }

(นิพจน์เงื่อนไขแบบ "ธรรมดา" ที่มีตัวดำเนินการทางคณิตศาสตร์แบบเลขฐานสองในคำสั่งแรก) หรือ:

(( $(id -u) == 0 )) || { echo >&2 "Must be root to run script"; exit 1; }

(การประเมินผลทางคณิตศาสตร์สำหรับการทดสอบครั้งแรก)

สังเกตเห็นการเปลี่ยนแปลง()-> {}- วงเล็บปีกกาไม่วางไข่ subshell (ค้นหาman bash"subshell")


1
โปรดออกด้วยรหัสอื่นที่ไม่ใช่ศูนย์ตัวอย่าง: exit 1เพื่อให้เข้าใจถึงกระบวนการหลักที่เกิดปัญหาขึ้น
SamK

1
คุณไม่ควรใช้สำหรับการเปรียบเทียบตัวเลขการใช้งาน[[ ((
Chris Down

1
@ChrisDown [[ดีตราบใดที่คุณใช้แทน-eq ==
Let_Me_Be

แก้ไขเงื่อนไขเพิ่มเวอร์ชันคณิตศาสตร์ @ChrisDown
Mat

2
@ แมทอย่างไรก็ตามคุณสามารถย่อให้สั้นลงได้(( EUID )) && ...
Chris Down

21

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

if [[ `id -u` != 0 ]]; then
    echo "Must be root to run script"
    exit
fi

ดังนั้นจึงไม่มีวิธีที่จะทำเช่นนี้กับหนึ่งซับ?
Garrett Hall

1
ตรรกะของคุณย้อนหลัง ในตัวอย่างของคุณถ้าid -u == 0ซึ่งหมายความว่าคุณเป็นคนรูท [[ $(id -u) != 0 ]]; thenคุณต้องการ
ทิมเคนเนดี้

4
หากคุณ / ต้อง / มีซับในหนึ่งครั้งลองใช้กับขนาด: [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1;สังเกตด้วย$UIDเช่นกันซึ่งจะช่วยประหยัดกระบวนการวางไข่ $EUIDฉันคิดว่าคุณยังอาจต้องการ
janmoesen

1
@janmoesen จุดดี และในขณะที่กระจ้อยร่อยมีตัวแปรที่มีค่าตัวเลข: ((UID)) && echo 'You have to be root.' && exit 1.
จัดการ

3
@janmoesen: โปรดทราบว่าการใช้ตรรกะผกผันดังกล่าวจะทำให้สคริปต์ที่set -eจะยกเลิก [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1 || trueหนึ่งวิธีการแก้ปัญหาที่เป็น
sam hocevar

2

ด้วยทุบตี :

[ $UID -ne 0 ] && echo "Must be root to run script" && exit 1

นั่นจะล้มเหลวในการออกหากechoล้มเหลว (เช่นเนื่องจาก stdout ไม่สามารถเขียนได้)
Stéphane Chazelas

1

วงเล็บที่อยู่รอบ ๆ||และ&&ไม่จำเป็นเนื่องจากเป็นสิ่งที่เกี่ยวข้องกัน สองนิพจน์ต่อไปนี้เทียบเท่ากัน:

expr1 || expr2 && expr3
expr1 || { expr2 && expr3 }

ดังนั้น&&แทนที่จะ;ทำงานได้ดีเหมือนechoจะกลับมาจริง

[[ $(id -u) == 0 ]] || echo "Must be root to run script" && exit 1

1
ในขณะที่ทุกสิ่งที่คุณพูดถูกต้องนี่เป็นรูปแบบที่ไม่ดีที่จะเรียนรู้เพราะคุณต้องพึ่งพาค่าส่งคืนของ expr2 คุณแน่ใจหรือว่าเสียงสะท้อนจะส่งคืนสถานะการออก 0 เสมอ? ควรจัดกลุ่มข้อความด้วยเครื่องหมายปีกกาและเซมิโคลอน นี่เป็นข้อผิดพลาดทั่วไปที่มีรายการของตัวเองใน BashPitfalls: mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3
Flimm

1
@Flimm: ฉันไม่เห็นด้วยกับรูปแบบที่ไม่ดี เห็นได้ชัดว่ามันใช้ขึ้นอยู่กับกรณีและยังขึ้นอยู่กับความรู้ของคุณของค่าตอบแทนที่คุณจะได้รับ ในกรณีนี้ฉันแน่ใจว่าเสียงก้องจะส่งกลับ 0 เป็น 99.999% ของเวลาและถ้ามันหยุดข้อผิดพลาดในการเขียน (ในกรณีเดียวมันจะไม่กลับ 0) มีปัญหาใหญ่กว่า expr นี้ นอกจากนี้ยังมีกรณีที่คุณกำลังสร้างค่าตอบแทนดังนั้นไม่ใช่มันไม่ใช่ "รูปแบบที่ไม่ดี" สำหรับฉัน
ata

ฉันจะเพิ่มเช่นเดียวกับที่ระบุไว้ในวิกิว่าคุณควรใช้มันหากแน่ใจว่าเข้าใจการประเมิน C อย่างไรก็ตามการทดสอบเล็กน้อยควรกำจัดความคลุมเครือใด ๆ
ata

0

สิ่งนี้อาจช่วยคุณได้ในการทุบตี

[oracle@rac1 ~]$ which bash
/bin/bash
[oracle@rac1 ~]$ cat test1.sh
if [ `id -u` != 0 ]
then
echo "Must be root to run the script
 "
exit
fi

3
สิ่งนี้ได้รับการตอบและยอมรับแล้ว นอกจากนี้คำตอบของคุณใกล้เคียงกับสิ่งที่โพสต์แล้ว
maulinglawns

@ maulinglawns คำตอบนั้นตรงกันข้ามกับคนอื่น ๆ ที่ได้รับประโยชน์จากการพกพาไปยังเชลล์เหมือนบอร์นทั้งหมด (มันจะดีกว่าถ้าข้อผิดพลาดถูกส่งออกใน stderr สถานะทางออกไม่เป็นศูนย์และการทดแทนคำสั่งถูกอ้างถึงแม้ว่า )
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.