สคริปต์ทุบตี [x $ 1 = x]


21

ฉันกำลังอ่านสคริปต์ทุบตีฉันไม่เข้าใจว่าเกิดอะไรขึ้น

#!/bin/sh
[ x$1 = x ] 

เกิดอะไรขึ้นกับบรรทัดที่สองและ[ x$1 = x ] หมายถึงอะไร

คำตอบ:


27

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


ใช่คุณไม่ควรทำแบบนี้อีกแล้วนำสไตล์ที่ทันสมัยมาใช้ นอกจากว่าคุณกำลังทำงานกับ PDP11
MacLemon

4
มันไม่เกี่ยวกับสตริงว่างเปล่ามากนัก [ x$1 = x ]ยังคงไม่ถูกต้อง แต่[ "x$1" = x ]จะใช้สำหรับเชลล์ที่มีปัญหาซึ่ง$1อยู่!หรือ(หรือ-n.... [ "" = "$1" ]และcase $1 in "")ก็อาจใช้ได้เช่นกัน
Stéphane Chazelas

2
@ MacLemon ไม่จำเป็นต้องย้อนกลับไป [ -z "$1" ]และ[ "$1" = "" ]ยังไม่สามารถใช้งานได้กับ / bin / sh ของ Solaris 10 ซึ่งเป็นรุ่นเดิมที่มีเส้นประ -5.4
Stéphane Chazelas

1
+1 พิเศษสำหรับประโยคสุดท้าย!
เกล็นแจ็คแมน

1
@glennjackman ประโยคสุดท้ายนั้นไม่ถูกต้อง Solaris 10 ยังคงเป็นเวอร์ชันที่ใช้กันอย่างแพร่หลายที่สุดของ Solaris และ[ "$1" = "" ]ยังไม่สามารถใช้งานได้/bin/sh(แม้ว่าคุณต้องการใช้งานที่/usr/xpg4/bin/shนั่นไม่ใช่/bin/sh) เส้นประได้รับการแก้ไขในเรื่องนั้นในเดือนมกราคม 2009
Stéphane Chazelas

8

วงเล็บเหลี่ยมบ่งบอกถึงการทดสอบดังนั้น[ x$1 = x]โดยไม่มีifหรือสิ่งที่คล้ายกันนั้นไม่มีความหมาย

มันหมายถึงการประเมินว่าเป็นจริงหากx$1ขยายไปxและผิดเป็นอย่างอื่น แต่เนื่องจากไม่ได้ระบุไว้หาก$1เป็น (เช่น) "เฮ้ x" เชลล์จะเห็นx = xดังนั้นการก่อสร้างนี้จึงไม่ปลอดภัย

วัตถุประสงค์ของการx = xตรวจสอบคือการตรวจสอบว่าตัวแปรว่างเปล่า วิธีทั่วไปในการทำเช่นนี้คือเพียงใช้เครื่องหมายคำพูด:

if [ "$1" = "" ]; then

ผู้ประกอบการทดสอบทุบตี-zและ-nยังสามารถนำมาใช้ แต่พวกเขาจะน้อยพกพาไปยังเปลือกประเภทอื่น ๆ 1

เหตุผลของราคาหรือx$1คือเพื่อให้ด้านซ้ายไม่ขยายไปเป็นอะไรซึ่งจะเป็นข้อผิดพลาดทางไวยากรณ์:

if [  = x ]  # No good!
if [ "" =  "" ] # Okay.
if [ x = x ] # Also okay.

1. จริงๆแล้วtestสามารถเป็นยูทิลิตี้แบบสแตนด์อโลน แต่เชลล์ส่วนใหญ่จะใช้มันเป็นแบบในตัว ตรวจสอบความแตกต่างระหว่างและwhich test type testบน GNU / Linux man testการเรียกร้องในการอ้างถึงในตัว แต่ถ้าคุณโทร (เช่น) /usr/bin/test, ยูทิลิตี้ที่ดูเหมือนว่าจะดำเนินการมีการบันทึกไว้ในหน้าคนรวมทั้งและ-z-n


1
[ x$1 = x ]จะประเมินผลเป็นจริง$1เช่น" -o x"กัน ลองsh -xc '[ x$1 = x ] && echo yes' sh ' -o x'ดู [ x$1 = x ]ผิดและไม่สมเหตุสมผล
Stéphane Chazelas

@ StéphaneChazelasขอบคุณ SC - แก้ไข (ย่อหน้าที่ 2)
goldilocks

คุณไม่จำเป็นต้องifไปใช้งานที่testคุณสามารถใช้มันก่อน &&, ||หรือหลังwhileหรือตรวจสอบผลการใช้$?
Jasen

8
[ x$1 = x ]

เข้าท่าzshเท่านั้น ที่เปรียบเทียบเรียงต่อกันของกับอาร์กิวเมนต์แรกของสคริปต์เพื่อx xดังนั้น[คำสั่งจะคืนค่าจริงถ้า$1ว่างหรือไม่ได้จัดเตรียมไว้

[ $1 = "" ]

จะไม่ทำงานเพราะในzshเมื่อตัวแปรว่างไม่ได้ถูกยกมาในบริบทรายการมันจะขยายเป็นไม่มีอาร์กิวเมนต์เลยแทนที่จะเป็นอาร์กิวเมนต์ว่างดังนั้นถ้าไม่$1ได้ตั้งค่าหรือว่างเปล่า[คำสั่งจะได้รับเป็นอาร์กิวเมนต์[เท่านั้น=สตริงว่าง และ]สิ่งที่มันไม่สมเหตุสมผล [ -z "$1" ]หรือ[ "$1" = "" ]จะโอเคเหมือนใน POSIX เชลล์

ในกระสุน Bourne-like / POSIX [ x$1 = x ]ไม่สมเหตุสมผล นั่นคือตัวดำเนินการแยก + glob นำไปใช้กับการต่อกันxและอาร์กิวเมนต์แรกของสคริปต์โดยหวังว่าผลลัพธ์และ=และxและ]ทำนิพจน์ทดสอบที่ถูกต้องสำหรับ[คำสั่ง

ตัวอย่างเช่นถ้าสคริปต์ที่ถูกส่งผ่านไปหนึ่ง" = x -o x ="อาร์กิวเมนต์[จะได้รับข้อโต้แย้งเหล่านั้น[, x, =, x, -o, x, =, x, ]ซึ่ง[จะเข้าใจเปรียบเทียบxกับxและxมีxและกลับจริง

ถ้า$1เป็น"* *"เช่นนั้นเชลล์จะส่งรายการ[คำสั่งของไฟล์ในไดเรกทอรีปัจจุบันที่ชื่อขึ้นต้นด้วยx(การขยายตัวกลมของx*) จากนั้นรายการของไฟล์ที่ไม่ซ่อน (การขยาย*) ... ซึ่ง[ไม่น่าจะสามารถทำได้ เพื่อทำให้ความรู้สึกใด ๆ ออกมาจาก กรณีเดียวที่จะทำทุกอย่างที่เหมาะสมคือถ้า$1ไม่มีอักขระตัวแทนหรืออักขระว่าง

ตอนนี้สิ่งที่คุณพบบางครั้งก็คือรหัสเช่น:

[ "x$1" = x ]

ที่ใช้ในการทดสอบว่า$1ว่างเปล่าหรือไม่มีการตั้งค่า

วิธีปกติในการทดสอบตัวแปรว่างหรือไม่ได้ตั้งค่าคือ:

[ -z "$1" ]

แต่ที่ล้มเหลวสำหรับบางค่า$1ชอบ=ในการใช้งานบางอย่าง (ไม่ใช่ POSIX) [เช่น builtin หนึ่งในเชลล์เป้าหมายที่พบ/bin/shใน Solaris 10 และก่อนหน้านี้หรือบางรุ่นเก่าdash(สูงถึง 0.5.4) หรือ BSD shบางรุ่น

นั่นเป็นเพราะ[เห็น[, -z, =, ]และบ่นเกี่ยวกับข้อโต้แย้งไปยัง=ผู้ประกอบการไบนารีแทนของการทำความเข้าใจว่ามันเป็น-zผู้ประกอบการเอกนำไปใช้กับ=สตริง

ในทำนองเดียวกัน[ "$1" = "" ]ล้มเหลวสำหรับการใช้งานบางอย่าง[ถ้า$1เป็นหรือ!(

ในเชลล์ / [การนำไปใช้งาน:

[ "x$1" = x ]

เป็นการทดสอบที่ถูกต้องเสมอโดยไม่คำนึงถึงค่าของ$1เช่น:

[ "" = "$1" ]

และ:

[ -z "${1:+x}" ]

และ

case $1 in "") ...; esac

แน่นอนถ้าคุณต้องการตรวจสอบว่าไม่มีการโต้แย้งใด ๆ คุณต้อง:

[ "$#" -eq 0 ]

นั่นคือคุณตรวจสอบจำนวนข้อโต้แย้งที่ส่งผ่านไปยังสคริปต์

โปรดทราบว่าในปัจจุบัน[ -z "$var" ]มีการระบุอย่างชัดเจนโดย POSIX และไม่สามารถล้มเหลวในการที่สอดคล้องกับ[การใช้งาน (และbashก็[เป็นและได้รับมานานหลายทศวรรษ) ดังนั้นคุณควรจะbashเชื่อถือได้ใน POSIX sh หรือสคริปต์


0

x$1กำลังเชื่อมโยงสองสตริงxและ$1และถ้า $ 1 ว่างเปล่า x $ 1 เท่ากับ x และ [x $ 1 = x] จะเป็นจริงตามผลลัพธ์ x = yใช้ในการเปรียบเทียบสตริงใน sh


2
ไม่มีการx$1อ้างถึงดังนั้นการแยกและการโค้งจะทำกับสิ่งเหล่านั้น
Stéphane Chazelas

0

[ x$1 = x ]เป็นจริงถ้า$1unset / null / ว่างเปล่าหรือไม่
ลองด้วยตัวคุณเอง:
TEST= ;[ x$TEST = x] && echo "TEST is unset"
และ
TEST=lolz ;[ x$TEST = x ] && echo "TEST is unset"


1
[ x$1 = x ]ก็เป็นความจริง$1เช่น" -o x"กัน ลองsh -xc '[ x$1 = x ] && echo yes' sh ' -o x'ดู [ x$1 = x ]ผิดและไม่สมเหตุสมผล
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.