มันเป็นเอกสาร (สำหรับ POSIX) ในส่วน 2.9.1 คำสั่งพื้นฐาน
ของ Open Group Base Specifications มีกำแพงข้อความอยู่ที่นั่น ฉันนำความสนใจของคุณไปยังย่อหน้าสุดท้าย:
หากมีชื่อคำสั่งการดำเนินการจะยังคงที่อธิบายไว้ในคำสั่งค้นหาและการดำเนินการ หากไม่มีชื่อคำสั่ง แต่คำสั่งที่มีการทดแทนคำสั่งคำสั่งจะต้องสมบูรณ์ด้วยสถานะออกจากการทดแทนคำสั่งสุดท้ายที่ดำเนินการ มิฉะนั้นคำสั่งจะสมบูรณ์ด้วยสถานะการออกเป็นศูนย์
ตัวอย่างเช่น
Command Exit Status
$ FOO=BAR 0 (but see also the note from icarus, below)
$ FOO=$(bar) Exit status from "bar"
$ FOO=$(bar) baz Exit status from "baz"
$ foo $(bar) Exit status from "foo"
นี่คือวิธีการทุบตีทำงานเช่นกัน แต่ดูส่วน "ไม่ง่าย" ในตอนท้าย
phkในคำถามของเขาการมอบหมายเป็นเหมือนคำสั่งที่มีสถานะออกยกเว้นเมื่อมีการทดแทนคำสั่ง? แนะนำ
... ดูเหมือนว่าการมอบหมายนั้นถือเป็นคำสั่ง ... โดยมีค่าการออกเป็นศูนย์ แต่จะใช้ก่อนที่ด้านขวาของการมอบหมาย (เช่นการแทนที่คำสั่งเรียก…)
นั่นไม่ใช่วิธีที่ดีในการดู โครงการดิบสำหรับการกำหนดสถานะการกลับมาของคำสั่งง่ายๆ (อย่างใดอย่างหนึ่งไม่ได้มี;
, &
, |
, &&
หรือ||
) เป็น:
- สแกนบรรทัดจากซ้ายไปขวาจนกว่าจะถึงจุดสิ้นสุดหรือคำสั่ง (โดยทั่วไปคือชื่อโปรแกรม)
- หากคุณเห็นการกำหนดตัวแปรสถานะการส่งคืนสำหรับบรรทัดอาจเป็น 0
- หากคุณเห็นการทดแทนคำสั่ง - เช่น
$(…)
- รับสถานะการออกจากคำสั่งนั้น
- หากคุณเข้าถึงคำสั่งจริง (ไม่ใช่ในการทดแทนคำสั่ง) ให้ใช้สถานะการออกจากคำสั่งนั้น
สถานะการส่งคืนสำหรับสายคือหมายเลขสุดท้ายที่คุณพบ
การแทนที่คำสั่งเป็นอาร์กิวเมนต์ของคำสั่งเช่นfoo $(bar)
จะไม่นับ foo
คุณจะได้รับสถานะออกจาก ในการถอดความสัญลักษณ์ของ phkพฤติกรรมที่นี่คือ
temporary_variable = EXECUTE( "bar" )
overall_exit_status = EXECUTE( "foo", temporary_variable )
แต่นี่เป็นเรื่องธรรมดามาก สถานะการคืนสินค้าโดยรวมจาก
A = $ ( cmd 1 ) B = $ ( cmd 2 ) C = $ ( cmd 3 ) D = $ ( cmd 4 ) E = mc 2
เป็นสถานะออกจาก
การกำหนดที่เกิดขึ้นหลังจากการกำหนดไม่ได้ตั้งค่าสถานะการออกโดยรวมเป็น 0
cmd4
E=
D=
icarusในคำตอบของเขาสำหรับคำถามของ phk , ยกประเด็นสำคัญ: ตัวแปรสามารถตั้งค่าเป็นอ่านได้อย่างเดียว ย่อหน้าที่สามถึงครั้งสุดท้ายในมาตรา 2.9.1 ของมาตรฐาน POSIXกล่าวว่า
หากการมอบหมายตัวแปรใด ๆ พยายามกำหนดค่าให้กับตัวแปรที่มีการตั้งค่าแอตทริบิวต์แบบอ่านอย่างเดียวในสภาพแวดล้อมเชลล์ปัจจุบัน (ไม่ว่าการมอบหมายนั้นจะเกิดขึ้นในสภาพแวดล้อมนั้น) จะเกิดข้อผิดพลาดในการกำหนดตัวแปร ดูผลที่ตามมาของข้อผิดพลาดของเชลล์สำหรับผลที่ตามมาของข้อผิดพลาดเหล่านี้
ดังนั้นถ้าคุณพูด
readonly A
C=Garfield A=Felix T=Tigger
สถานะกลับคือ 1. มันไม่สำคัญว่าถ้าสตริงGarfield
, Felix
และ / หรือTigger
จะถูกแทนที่ด้วยแทนคำสั่ง (s) - แต่ดูหมายเหตุด้านล่าง
ส่วนที่ 2.8.1 ผลที่ตามมาของข้อผิดพลาดของเชลล์มีข้อความอีกจำนวนหนึ่งและตารางและลงท้ายด้วย
ในทุกกรณีที่แสดงในตารางที่ไม่จำเป็นต้องมีเชลล์เชิงโต้ตอบเพื่อออกจากเชลล์เชลล์จะไม่ทำการประมวลผลคำสั่งเพิ่มเติมที่เกิดข้อผิดพลาดเพิ่มเติม
รายละเอียดบางอย่างสมเหตุสมผล บางคนไม่:
A=
มอบหมายบางครั้งถูกยกเลิกบรรทัดคำสั่งเป็นที่ประโยคสุดท้ายดูเหมือนว่าจะระบุ ในตัวอย่างด้านบนC
ถูกตั้งค่าเป็นGarfield
แต่T
ไม่ได้ตั้งค่า (และแน่นอนไม่มีทั้ง A
)
- ในทำนองเดียวกัน
รันแต่ไม่
แต่ในรุ่นของฉันทุบตี (ซึ่งรวมถึง 4.1.x และ 4.3.X) ก็ไม่ดำเนินการ (โดยบังเอิญนี่เป็นการตีความหมายของ phk เพิ่มเติมว่ามูลค่าการออกของการมอบหมายใช้ก่อนที่ด้านขวาของการมอบหมาย)
C=$(cmd1) A=$(cmd2) T=$(cmd3)
cmd1
cmd3
cmd2
แต่นี่เป็นความประหลาดใจ:
ในทุบตีรุ่นของฉัน
แบบอ่านอย่างเดียว
C = บางสิ่งบางอย่าง A = บางสิ่งบางอย่าง T = บางสิ่งบางอย่าง cmd 0
ไม่ดำเนินการ โดยเฉพาะอย่างยิ่ง,cmd0
C = $ ( cmd 1 ) A = $ ( cmd 2 ) T = $ ( cmd 3 ) cmd 0
รัน
และแต่ไม่ (หมายเหตุว่านี้เป็นตรงข้ามของพฤติกรรมของมันเมื่อมีคำสั่งไม่.) และจะกำหนด(เช่นเดียวกับ) ในสภาพแวดล้อมของ ฉันสงสัยว่านี่เป็นข้อผิดพลาดในทุบตีหรือไม่
cmd1
cmd3
cmd2
T
C
cmd0
ไม่ง่ายเลย:
ย่อหน้าแรกของคำตอบนี้อ้างถึง "คำสั่งง่าย ๆ "
สเปคบอกว่า
“ คำสั่งง่าย ๆ ” คือลำดับของการกำหนดตัวแปรและการเปลี่ยนเส้นทางที่เป็นทางเลือกในลำดับใดก็ได้ตามด้วยคำและการเปลี่ยนเส้นทางซึ่งสิ้นสุดลงโดยผู้ควบคุม
ข้อความเหล่านี้เป็นข้อความที่เหมือนในบล็อกตัวอย่างแรกของฉัน:
$ FOO=BAR
$ FOO=$(bar)
$ FOO=$(bar) baz
$ foo $(bar)
สามรายการแรกประกอบด้วยการกำหนดตัวแปรและสามรายการสุดท้ายรวมถึงการแทนที่คำสั่ง
แต่การมอบหมายตัวแปรบางอย่างนั้นไม่ง่ายนัก
ทุบตี (1)พูดว่า
งบที่ได้รับมอบหมายอาจปรากฏเป็นข้อโต้แย้งไปalias
, declare
, typeset
, export
, readonly
และlocal
ในตัวคำสั่ง ( ประกาศคำสั่ง)
สำหรับexport
, สเป POSIXกล่าวว่า
ออกจากสถานะ
0ส่งออกชื่อตัวถูกดำเนินการทั้งหมดเรียบร้อยแล้ว
> 0ส่งออกอย่างน้อยหนึ่งชื่อไม่ได้หรือระบุ-p
ตัวเลือกแล้วเกิดข้อผิดพลาด
และ POSIX ไม่รองรับlocal
แต่bash (1)พูดว่า
มันเป็นข้อผิดพลาดที่จะใช้local
เมื่อไม่ได้อยู่ในฟังก์ชั่น สถานะการส่งคืนคือ 0 ยกเว้นว่าlocal
ใช้นอกฟังก์ชั่นมีการระบุชื่อที่ไม่ถูกต้องหรือชื่อเป็นตัวแปรแบบอ่านอย่างเดียว
เมื่ออ่านระหว่างบรรทัดเราจะเห็นคำสั่งประกาศเช่นนั้น
export FOO=$(bar)
และ
local FOO=$(bar)
มีมากขึ้นเช่น
foo $(bar)
ตราบเท่าที่พวกเขาไม่สนใจสถานะออกจากbar
และให้คุณออกจากสถานะขึ้นอยู่กับคำสั่งหลัก ( export
, local
หรือfoo
) ดังนั้นเราจึงมีความประหลาด
Command Exit Status
$ FOO=$(bar) Exit status from "bar"
(unless FOO is readonly)
$ export FOO=$(bar) 0 (unless FOO is readonly,
or other error from “export”)
$ local FOO=$(bar) 0 (unless FOO is readonly,
statement is not in a function,
or other error from “local”)
ซึ่งเราสามารถสาธิตด้วย
$ export FRIDAY=$(date -d tomorrow)
$ echo "FRIDAY = $FRIDAY, status = $?"
FRIDAY = Fri, May 04, 2018 8:58:30 PM, status = 0
$ export SATURDAY=$(date -d "day after tomorrow")
date: invalid date ‘day after tomorrow’
$ echo "SATURDAY = $SATURDAY, status = $?"
SATURDAY = , status = 0
และ
myfunc() {
local x=$(echo "Foo"; true); echo "x = $x -> $?"
local y=$(echo "Bar"; false); echo "y = $y -> $?"
echo -n "BUT! "
local z; z=$(echo "Baz"; false); echo "z = $z -> $?"
}
$ myfunc
x = Foo -> 0
y = Bar -> 0
BUT! z = Baz -> 1
โชคดีที่ShellCheckจับข้อผิดพลาดและเพิ่มSC2155ซึ่งแนะนำว่า
export foo="$(mycmd)"
ควรเปลี่ยนเป็น
foo=$(mycmd)
export foo
และ
local foo="$(mycmd)"
ควรเปลี่ยนเป็น
local foo
foo=$(mycmd)
local
หรือไม่ว่ามีส่วนเกี่ยวข้องกับเรื่องนี้อย่างไร เช่นlocal foo=$(bar)
?