“ / bin / [” ทำงานอย่างไร


50

ฉันประหลาดใจเสมอที่ในโฟลเดอร์/binมี[โปรแกรม

นี่คือสิ่งที่เรียกว่าเมื่อเรากำลังทำอะไรเช่น: if [ something ]?

โดยการเรียก[โปรแกรมอย่างชัดเจนในเชลล์มันจะถามหาที่สอดคล้องกัน]และเมื่อฉันให้วงเล็บปิดมันดูเหมือนจะไม่ทำอะไรเลยไม่ว่าฉันจะแทรกอะไรระหว่างวงเล็บ

จำเป็นต้องพูดทางปกติเกี่ยวกับการให้ความช่วยเหลือเกี่ยวกับโปรแกรมไม่ทำงานเช่นค่าman [มิได้[ --helpงาน


11
@IporSircer [อ้างถึงtestคำสั่งแม้ว่าไม่exprควรดังนั้นman test
Sergiy Kolodyazhnyy

8
man '['ทำงานได้ดีสำหรับฉัน - ไม่ว่าคุณจะลืมพูด[หรือคุณมีคำจำกัดความที่แตกต่างกันของ "งาน"
Toby Speight

3
คำเตือนเล็กน้อย: [ประเมินอาร์กิวเมนต์ของมันดังนั้นคุณต้องมีช่องว่างระหว่างทั้งหมด [ a=b ]ไม่ใช่การเปรียบเทียบ: มันจะเป็นจริงเสมอ (เป็นสตริงเดียว: "a = b" ซึ่งประเมินเสมอเป็นจริง ) และคุณควร จำกัด จำนวนอาร์กิวเมนต์เป็น 4 (แม้ว่าการใช้งานล่าสุดจะอนุญาตมากกว่านี้ .. . การ จำกัด ที่ 4 ทำให้พกพาได้มากกว่าตัวอย่างเช่น: [ "a" = "b" ]มีอาร์กิวเมนต์ 4 ข้อแล้ว: "a" "=" "b" และสิ้นสุดการทดสอบที่ไม่จำเป็น ARG: "]") หากคุณต้องการข้อมูลเพิ่มเติม: ทดสอบลูกโซ่ด้วย:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Olivier Dulac

1
@OlivierDulac a !ด้วยตัวเอง (unescaped และ unquoted) จะไม่ถูกแทนที่และดียิ่งขึ้นกว่าif ! [ ...นี้ การขยายตัวของ bash ทั้งหมดที่ใช้!รวมถึงตัวละครอื่นเป็นอย่างน้อย
muru

3
นอกจากนี้คุณควรทราบว่ายังมี[-builtin ในbash(และอาจจะเปลือกหอยอื่น ๆ เช่นกัน) /bin/[และว่าเรื่องนี้อาจนำมาใช้แทน นอกจากนี้ยังมีtest- คำสั่งซึ่งในหลาย ๆ ระบบเป็นลิงก์สัญลักษณ์ไปยัง/bin/[(หรือกลับกัน) - แต่สำหรับคนอื่น ๆ เป็นคำสั่งแยกต่างหาก
Baard Kopperud

คำตอบ:


63

[งานคำสั่งคือการประเมินการแสดงออกการทดสอบ มันกลับมาพร้อมกับสถานะการออก 0 (นั่นหมายถึงจริง ) เมื่อนิพจน์แก้ไขให้เป็นจริงและอย่างอื่น (ซึ่งหมายถึงเท็จ )

ไม่ใช่ว่ามันจะไม่ทำอะไรเลยมันเป็นเพียงแค่ผลลัพธ์ของมันที่จะพบได้ในสถานะทางออก ในเชลล์คุณสามารถค้นหาข้อมูลเกี่ยวกับสถานะการออกของคำสั่งสุดท้ายใน$?เชลล์เหมือน Bourne หรือ$statusในเชลล์อื่น ๆ ส่วนใหญ่ (fish / rc / es / csh / tcsh ... )

$ [ a = a ]
$ echo "$?"
0
$ [ a = b ]
$ echo "$?"
1

ในภาษาอื่น ๆ เช่นperlสถานะออกจะถูกส่งกลับเช่นในค่าตอบแทนของsystem():

$ perl -le 'print system("[", "a", "=", "a", "]")'
0

โปรดทราบว่าเชลล์เหมือน Bourne ที่ทันสมัยทั้งหมด (และfish) มี[คำสั่งในตัว หนึ่งใน/binจะมักจะได้รับการดำเนินการเมื่อคุณใช้เปลือกอีกหรือเมื่อคุณทำสิ่งที่ชอบenv [ foo = bar ]หรือfind . -exec [ -f {} ] \; -printหรือว่าperlคำสั่งดังกล่าว ...

[คำสั่งนอกจากนี้ยังเป็นที่รู้จักกันโดยtestชื่อ เมื่อเรียกว่าเป็นtestมันไม่จำเป็นต้องมี]อาร์กิวเมนต์ปิด

ในขณะที่ระบบของคุณอาจไม่ได้มีหน้าคนสำหรับมันอาจจะมีหนึ่งสำหรับ[ testแต่อีกครั้งโปรดทราบว่ามันจะบันทึกเอกสาร/bin/[หรือ/bin/testการใช้งาน หากต้องการทราบเกี่ยวกับ[builtin ในเชลล์คุณควรอ่านเอกสารประกอบสำหรับเชลล์ของคุณแทน

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับประวัติศาสตร์ของยูทิลิตี้ที่และความแตกต่างกับการ[[...]]แสดงออกของการทดสอบ ksh คุณอาจต้องการที่จะได้ดูที่นี้Q & A อื่น ๆ ที่นี่


ดีเช่นเคย คุณอาจต้องการเพิ่มความคิดเห็นที่ฉันเพิ่มไว้ใต้ @Bregalad คำถาม? หรืออาจจะบางคนพิเศษ? ด้วยวิธีนี้คำตอบจะสมบูรณ์ยิ่งขึ้นใน "วิธีการทำงาน" (ฉันทราบว่าคุณได้ให้ข้อมูลที่เร่งด่วนเกี่ยวกับ "]" มากกว่าที่ฉันทำ ^^)
Olivier Dulac

“ทั้งหมดหอยบอร์นเหมือน (ปลา) มีในตัว [คำสั่ง” นั่นเป็นความจริงในทางปฏิบัติในศตวรรษที่ 21 [แต่ผมค่อนข้างมั่นใจว่าผมเคยใช้เปลือกโดยไม่ต้อง ฉันจำไม่ได้ว่ามันเป็นตัวแปร Bourne หรือเถ้ารุ่นโบราณ
Gilles 'SO- หยุดความชั่วร้าย'

@Gilles เชลล์เป้าหมายนำมาใช้ทั้งใน[และtestในตัวด้วย Unix System III ก่อนหน้านั้นไม่มี[และtestเป็นเพียงคำสั่งไบนารีภายนอก
jlliagre

@Gilles, เถ้าเดิมที่เคยทดสอบ builtin (รวมกับ expr) แต่เลือก ตามin-ulm.de/~mascheck/various/ash BSDs ไม่มีการทดสอบในตัวจนกระทั่งประมาณปี 2000 ฉันได้เพิ่ม "modern"
Stéphane Chazelas

ทำไมในโลกที่คุณต้องการจะทำfind . -exec [ f {} ] \; -print? คำสั่งที่find . -type f -printจะทำในสิ่งเดียวกันเพื่อให้มีประสิทธิภาพมากขึ้น ...
นี้ไม่ได้เป็นชื่อจริงของฉัน

41

ฉันประหลาดใจเสมอที่ในโฟลเดอร์/binมี[โปรแกรม

คุณมีสิทธิ์ที่จะประหลาดใจ นั่นเป็นหนึ่งในคำสั่ง POSIX ที่หายากพร้อมยูทิลิตี้ null ( :) ที่ไม่เกี่ยวข้องกับคำสั่งที่อนุญาตให้ใช้แบบอักษรของไฟล์ (ชุดอักขระชื่อไฟล์แบบพกพา)

สิ่งที่เรียกว่าเมื่อเราทำอะไรเช่น: if [ something ]?

แม่นยำ แต่ก็สามารถใช้งานได้โดยไม่ต้องใช้ifมากเกินไป

โดยการเรียก[โปรแกรมอย่างชัดเจนในเชลล์มันจะถามหาที่สอดคล้องกัน]และเมื่อฉันให้วงเล็บปิดมันดูเหมือนจะไม่ทำอะไรเลยไม่ว่าฉันจะแทรกอะไรระหว่างวงเล็บ

มันไม่สามารถมองเห็นได้ แต่จริง ๆ แล้วมันทำสิ่งเดียวกันมากกว่าเมื่อใช้กับifเช่นมันตั้งค่าสถานะการออกเป็น 0 (จริง) หรือสิ่งอื่น (เท็จ) ขึ้นอยู่กับสิ่งที่คุณใส่ในวงเล็บ มันเป็น (ด้วยเหตุผล) พฤติกรรมเช่นเดียวกับtestคำสั่ง; ]ความแตกต่างเพียงอย่างเดียวคือว่ามันจะมองหาตอนจบ ดูman testรายละเอียดที่

จำเป็นต้องพูดทางปกติเกี่ยวกับการให้ความช่วยเหลือเกี่ยวกับโปรแกรมไม่ทำงานเช่นค่าman [มิได้[ --helpงาน

ขึ้นอยู่กับระบบปฏิบัติการของคุณ man [ใช้งานได้จริงสำหรับฉันในการกระจาย Gnu / Linux สองกระแสหลัก แต่ไม่ได้อยู่บน Solaris

[ --help]อาจจะทำงานได้หรือไม่ขึ้นอยู่กับการดำเนินการในขณะที่มันจะทำลายไวยากรณ์แล้วหายไปตอนจบ นอกจากนี้มาตรฐาน POSIX สำหรับtest/ [คำสั่งจะออกกฎตัวเลือกทั้งหมดอย่างชัดเจนรวมถึงการ--ยกเลิกตัวเลือกเพื่อให้ทั้งสอง[ --help ]และtest --helpจำเป็นต้องส่งคืนtrueและปิดเสียงโดยการออกแบบ โปรดทราบว่าสิ่งที่คุณใส่ในวงเล็บหรือหลัง[และที่มีลักษณะเหมือนตัวเลือก (เช่น-f file, -n stringและชอบ) ไม่ได้เป็นตัวเลือกแต่ตัวถูกดำเนินการ

ทั้งหมดที่ทันสมัยบอร์นล่ามเปลือกสไตล์ (เช่นbash, ksh, dashและzshเพื่อชื่อไม่กี่) ใช้test/ [ยูทิลิตี้ภายในเป็น builtin ดังนั้นเมื่อคุณใช้พวกเขาหน้าคู่มือที่เหมาะสมในการอ้างถึงอาจจะเป็นหนึ่งในของเปลือกไม่testอย่างใดอย่างหนึ่ง

ก่อนหน้า Unix System III (1981) เชลล์ Bourne ไม่ได้ใช้testยูทิลิตีเป็นบิวอินเพื่อให้มีการใช้งานคำสั่งไบนารีภายนอกเท่านั้น ไม่มีทั้ง[คำสั่ง (ภายในหรือ builtin) จนกระทั่ง Unix System III ดังนั้นตัวอย่างเช่นภายใต้ Unix เวอร์ชัน 7 คุณต้องพิมพ์:

if test something ; then

แทน:

if [ something ] ; then

"ผู้ชาย [ทำงานได้ดีสำหรับฉันบนการแจกแจงหลักของ Gnu / Linux" อืม .. Centos (ยังคงเป็นที่ยอมรับ 6.8) ยังไม่ชัดเจนเพียงพอ :) ใช้ man testงานได้ แต่ไม่ใช่man [ ในอีกทางหนึ่งสภาพแวดล้อมที่ cygwin ของฉันไม่เป็นที่รู้จักman [!
อดัม

1
@ อดัมใช่คุณพูดถูกมันเร็วกว่าที่ฉันคิดไว้แม้ว่าฉันจะไม่ได้เขียนดิสทริบิวชั่นลีนุกซ์ทุกตัวแต่มันก็ใช้ได้กับฉัน (เช่นที่ฉันทดสอบ) นั่นคือโคลนนิ่ง OL 7.2 (RHEL 7.2) และมิ้นต์ 17.1 (Ubuntu 14.04)
jlliagre

man [ดูเหมือนจะไม่ทำงานกับ Manjaro (อิงตาม Linux Arch) คู่มือสำหรับtestรายการ[ --helpเป็นอุทธรณ์ที่ถูกต้องที่ควรจะแสดงความช่วยเหลือ แต่ที่น่าสนใจก็ไม่ได้และแทนที่จะบ่นเกี่ยวกับที่ขาดหายไปเช่นเดียวกับ] --versionเพิ่ม]ไม่ได้ทำอะไรเพื่อให้ดูเหมือนเป็นไปไม่ได้ที่จะได้รับความช่วยเหลืออื่น ๆ man testที่นอกเหนือจาก
Darkhogg

@Darkhogg คุณสามารถลองหรือ/usr/bin/[ --help /bin/[ --help
jlliagre

1
@jlliagre คุณพูดถูกฉันใช้ builtins แล้ว env [ --helpเช่นเดียวกับการ/usr/bin/[ --helpทำงานอย่างสมบูรณ์ดี (แม้ว่าฉันจะต้องอ้าง/usr/bin/[หรือ zsh บ่น)
Darkhogg

10

[เป็นที่รู้จักกันทั่วไปว่าเป็นtestคำสั่ง การใช้คำสั่งนี้โดยทั่วไปคือเพื่อประเมินค่านิพจน์และส่งคืนเงื่อนไข - จริงหรือเท็จ มันมักจะใช้ในif-then-else-fiงบแม้ว่ามันจะสามารถใช้นอกifงบเพื่อเรียกใช้คำสั่งอื่น ๆ อย่างมีเงื่อนไขผ่านเปลือกของ&&หรือ||ผู้ประกอบการเช่นนั้น

$ [ -e /etc/passwd  ] && echo "File exists"
File exists

$ test -e /etc/passwd && echo "File exists"
File exists

โดยเฉพาะอย่างยิ่งการประเมินผลจะถูกสื่อสารไปยังคำสั่งอื่น ๆ ผ่านสถานะออก บางโปรแกรมอาจเลือกที่จะออกสถานะทางออกเพื่อแสดงถึงประเภทของเหตุการณ์ที่แตกต่างกัน - โปรแกรมเสร็จสมบูรณ์, ข้อผิดพลาดของประเภทเฉพาะที่เกิดขึ้นระหว่างการทำงานหรือข้อผิดพลาดทางไวยากรณ์ ในกรณีของtestคำสั่งมีความ0หมายจริงและ1หมายถึงเท็จ 2ในฐานะที่เป็นสเตฟานชี้ให้เห็นข้อผิดพลาดของไวยากรณ์การผลิตออกจากสถานะของ

man [สถานที่มันขึ้นอยู่กับระบบของคุณและมันยังได้อธิบายถึงเหตุผลที่คุณไม่ได้เห็นหน้าคนเมื่อคุณได้ ยกตัวอย่างเช่นใน FreeBSD /binจะอยู่ภายใต้ บน Linux (หรือในกรณีโดยเฉพาะอย่างยิ่งของฉัน Ubuntu 16.04) /usr/bin/มันอยู่ใน หากคุณทำman [หรือman testบนระบบ Linux คุณจะเห็นเอกสารเดียวกันเปิดอยู่ testนอกจากนี้ยังเป็นสิ่งสำคัญที่จะทราบว่าเปลือกของคุณอาจจะมีการดำเนินการของตัวเองของ

ควรสังเกตว่าคำสั่งนี้มีปัญหาซึ่งการใช้งานของ Korn เชลล์ (หรือที่รู้จักกันทั่วไปว่าการอ้างอิง"นิพจน์เงื่อนไข"กับวงเล็บเหลี่ยมสองชั้น[[ "$USER" = "root" ]]) พยายามแก้ไข คุณลักษณะนี้ยังใช้โดยเปลือกหอยอื่น ๆ เช่นและbashzsh


/usr/bin/สำหรับ Amazon Linux เช่นกัน
franklinsijo

@ StéphaneChazelasขอบคุณ ตอบแก้ไขแล้วตาม
Sergiy Kolodyazhnyy

3

ทั้งman [มิได้[ --helpงาน

ในบาง distros (เช่น Ubuntu) man [ดังนี้ symlink test(1)ไป สำหรับคนอื่น ๆ (เช่น Arch) นี่ไม่ใช่กรณี (แต่testหน้า man จะใช้เอกสาร[ด้วย)


type -a [ แสดงให้คุณเห็นว่ามีทั้งเชลล์ในตัวและตัวปฏิบัติการ

$ type -a [
[ is a shell builtin
[ is /usr/bin/[

bash-builtin [ --helpเพียงพิมพ์ข้อความแสดงข้อผิดพลาด (แต่เนื่องจากเป็น builtin คุณสามารถใช้help [หรือดู bash man page / docs)

/usr/bin/[ --help พิมพ์เอาต์พุตความช่วยเหลือแบบเต็ม (สำหรับ GNU Coreutils เวอร์ชัน) ซึ่งเริ่มด้วย:

$ /usr/bin/[ --help
Usage: test EXPRESSION
  or:  test
  or:  [ EXPRESSION ]
  or:  [ ]
  or:  [ OPTION
Exit with the status determined by EXPRESSION.

      --help     display this help and exit
      --version  output version information and exit

แล้วอธิบายไวยากรณ์ที่อนุญาตสำหรับ EXPRESSION

นี่เป็นอีกวิธีหนึ่งที่คุณสามารถค้นพบสิ่งนั้น[และtestเท่าเทียมกัน


BTW ถ้าคุณเขียนโปรแกรมสำหรับทุบตี (หรือเขียนหนึ่งสมุทรโต้ตอบ) ผมอยากแนะนำให้แทน[[ [มันจะดีกว่าในหลาย ๆ ด้านดูลิงก์ในคำตอบของ Serg


2

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

เช่น:

[ hello ]
echo "Exit-status of [ hello ] is:" $?
[ abc = abc ]
echo "Exit-status of [ abc = abc ] is:" $?
[ ]
echo "Exit-status of [ ] is:" $?
[ abc = def ]
echo "Exit-status of [ abc = def ] is:" $?

…จะส่งออก:

Exit-status ของ [hello] คือ: 0       - เนื่องจากสตริงที่ไม่ว่างถือว่าเป็นจริง 
Exit-status ของ [abc = abc] คือ: 0   - เพราะ 'abc' เป็นจริงเหมือนกับ 'abc' 
Exit-status ของ [] คือ : 1             - เนื่องจากสตริงว่างถือว่าเป็น 
สถานะออกที่ผิดของ [abc = def] คือ: 1   - เนื่องจาก 'abc' แตกต่างจาก 'def' จริงๆ

อย่างไรก็ตาม, bashและ shell อื่น ๆ มักจะไม่เรียกใช้/bin/[(หรือ/usr/bin/[) ในกรณีเหล่านี้, แต่เรียกใช้คำสั่งในตัวที่มีการทำงานเหมือนกันทุกประการ (แทนเหตุผลด้านประสิทธิภาพ) ในการเรียกใช้/bin/[(ไม่ใช่เชลล์ตัวแทนในตัว) คุณต้องระบุพา ธ ของมันอย่างชัดเจน (เช่น/bin/[ hello ]คุณไม่จำเป็นต้องใส่คำนำหน้า]ด้วย dirname แม้ว่า☺ ) หรือกำหนดค่าเชลล์ไม่ให้ใช้ตัวแทนในตัว (ตัวอย่างเช่นenable -n [ในทุบตี)

PS: ตามที่ได้กล่าวในคำตอบอื่น ๆที่เกี่ยวข้องกับ[ testแต่testแตกต่าง[ไม่จำเป็นต้อง]เป็นอาร์กิวเมนต์สุดท้าย(และไม่ได้คาดหวังเลย; เพิ่มพิเศษ]เพื่อtestการขัดแย้งสามารถทำให้เกิดการล้มเหลวด้วยข้อผิดพลาดหรือจะกลับผลผิด) และสามารถแก้ปัญหาให้กับไฟล์เดียวกัน (เช่นหนึ่งsymlinkedในกรณีนี้การเบี่ยงเบนพฤติกรรมอาจจะดำเนินการโดยการวิเคราะห์คำสั่งในปัจจุบันที่เรียกว่าภายใน/ รหัสตัวเอง) หรือไฟล์ที่แตกต่างกัน สำหรับเชลล์มักจะเรียกใช้ตัวแทนในตัวยกเว้นว่ามีการระบุเส้นทางอย่างชัดเจน ( ) หรือมีการกำหนดค่าไม่ให้ทำเช่นนั้น (/bin/test/bin/[test[test/bin/testenable -n test)

PPS: ไม่เหมือนtestและ[ทันสมัยifไม่เคยเป็นไฟล์จริง มันเป็นส่วนหนึ่งของเชลล์ (เช่นทุบตี) ไวยากรณ์: if commandA; then commandB; fi(ขึ้นบรรทัดใหม่สามารถใช้แทนอัฒภาค) ทำให้เกิดcommandBการดำเนินการถ้าและเพียงอย่างเดียวถ้าcommandAออกจากที่มีสถานะเป็นศูนย์ นี้ได้อย่างสมบูรณ์แบบเหมาะกับพฤติกรรมของtestหรือ[ช่วยให้การรวมพวกเขาเช่นif [ "$a" = foo ]; then …; fi (หรือif test "$a" = foo; then …; fi- เพียงน้อยอ่าน) อย่างไรก็ตามสคริปต์ที่ทันสมัยมักใช้[[แทนtestหรือ[ซึ่ง (ในฐานะif) ไม่เคยเป็นไฟล์จริง แต่มักจะเป็นส่วนหนึ่งของไวยากรณ์เชลล์

PPPS: สำหรับman- อย่าคาดหวังว่าmanจะมีบทความเกี่ยวกับทุกคำสั่งในระบบไฟล์ของคุณ ข้อมูลในบางส่วน (แม้ "ของจริง" แฟ้ม-based) คำสั่งอาจจะหายไปข้อมูลในบางเปลือกตัว -ins บางทีปัจจุบันไม่เพียง แต่ในบทความที่อุทิศตนเพื่อเปลือกที่เฉพาะเจาะจง (ที่สถานที่ที่คุณมากที่สุดอย่างแน่นอนจะพบข้อมูลเกี่ยวกับtest, [, if, [[) ยังคงกระจายจำนวนมากมีความชัดเจนman-articles สำหรับและtest [(เกี่ยวกับ--helpมันไม่ได้รับการยอมรับด้วยtestเหตุผลที่ชัดเจน: มันต้องจัดการกับกรณีอย่างเงียบ ๆ เช่นa=--help; test "$a"; ในการแจกแจงบางอย่าง[ --help(โดยไม่ปิด]) ยังคงแสดงความช่วยเหลือในบางกรณีมันไม่ได้)


3
โปรดทราบว่าifเป็นคำสั่งจนถึง Unix V6 Unix V7 (1979) มาพร้อมกับเชลล์เป้าหมาย (พร้อมif-then-else-fiโครงสร้าง) และtestคำสั่งใหม่
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.