ถ้าฉันวิ่ง
export TEST=foo
echo $TEST
มันส่งผลฟู
ถ้าฉันวิ่ง
TEST=foo echo $TEST
มันไม่ใช่. ฉันจะรับฟังก์ชั่นนี้โดยไม่ใช้การส่งออกหรือสคริปต์ได้อย่างไร
ถ้าฉันวิ่ง
export TEST=foo
echo $TEST
มันส่งผลฟู
ถ้าฉันวิ่ง
TEST=foo echo $TEST
มันไม่ใช่. ฉันจะรับฟังก์ชั่นนี้โดยไม่ใช้การส่งออกหรือสคริปต์ได้อย่างไร
คำตอบ:
นี่เป็นเพราะเชลล์ขยายตัวแปรในบรรทัดคำสั่งก่อนที่มันจะรันคำสั่งและในเวลานั้นตัวแปรนั้นไม่มีอยู่จริง ถ้าคุณใช้
TEST=foo; echo $TEST
มันจะทำงาน.
export
จะทำให้ตัวแปรปรากฏในสภาพแวดล้อมของคำสั่งที่ถูกเรียกใช้งานในภายหลัง (สำหรับวิธีการทำงานของ bash see help export
) หากคุณต้องการให้ตัวแปรปรากฏในสภาพแวดล้อมของคำสั่งเดียวให้ใช้สิ่งที่คุณได้ลองแล้วเช่น:
TEST=foo your-application
$TEST
ก่อนที่จะดำเนินการบรรทัดคำสั่ง เมื่อecho
มีการทำงาน (ยังทราบว่าecho
โดยปกติจะแปลเป็นคำสั่งในตัวเชลล์และไม่ให้/bin/echo
) มันจะเห็นการตั้งค่าตัวแปรในสภาพแวดล้อมของมัน อย่างไรก็ตามecho $TEST
อย่าบอกecho
ให้เอาท์พุทเนื้อหาของตัวแปรTEST
จากสภาพแวดล้อมของมัน มันบอกให้เชลล์ทำงานecho
ด้วยการโต้แย้งว่าอะไรก็ตามที่อยู่ในตัวแปรที่เรียกว่าTEST
- และสิ่งเหล่านี้เป็นสองสิ่งที่แตกต่างกันมาก
var=value sh -c 'echo "$var"'
?
"… $var …"
) แต่ไม่ใช่ในเครื่องหมายคำพูดเดี่ยว (เช่น'… $var …'
) เนื่องจากecho "$var"
อยู่ในเครื่องหมายคำพูดเดี่ยวสตริงทั้งหมดจึงถูกส่งผ่านไปยังsh -c
เชลล์( ) ใหม่โดยไม่ต้องตีความโดยเชลล์เชิงโต้ตอบภายนอก … (ต่อ)
sh -c
เปลือกใหม่ ( )
ฉันสงสัยว่าคุณต้องการให้ตัวแปรเชลล์มีขอบเขต จำกัด แทนที่จะเป็นตัวแปรสภาพแวดล้อม ตัวแปรสภาวะแวดล้อมคือรายการของสตริงที่ส่งไปยังคำสั่งเมื่อถูกเรียกใช้งาน
ใน
var=value echo whatever
คุณกำลังส่งผ่านvar=value
สตริงไปยังสภาพแวดล้อมที่เสียงสะท้อนได้รับ แต่echo
ไม่ได้ทำอะไรกับรายการสภาพแวดล้อมและการอยู่แล้วในเปลือกหอยส่วนใหญ่echo
ถูกสร้างขึ้นในและดังนั้นจึงไม่ดำเนินการ
ถ้าคุณเขียน
var=value sh -c 'echo "$var"'
นั่นจะเป็นอีกเรื่องหนึ่ง ที่นี่เรากำลังผ่านvar=value
ไปยังsh
คำสั่งและsh
เกิดขึ้นกับการใช้สภาพแวดล้อม หอยแปลงแต่ละตัวแปรที่พวกเขาได้รับจากสภาพแวดล้อมของพวกเขาให้กับตัวแปรเปลือกดังนั้นvar
ตัวแปรสภาพแวดล้อมsh
ที่ได้รับจะถูกแปลงเป็น$var
ตัวแปรและเมื่อมันขยายตัวในที่บรรทัดคำสั่งที่จะกลายเป็นecho
echo value
เนื่องจากสภาพแวดล้อมนั้นเป็นค่าเริ่มต้นที่สืบทอดมาecho
จะได้รับvar=value
ในสภาพแวดล้อมของมันด้วย (หรือหากถูกเรียกใช้) แต่อีกครั้งecho
ไม่สนใจสภาพแวดล้อม
ทีนี้ถ้าอย่างที่ฉันสงสัยสิ่งที่คุณต้องการคือการ จำกัด ขอบเขตของตัวแปรเชลล์มีหลายวิธีที่เป็นไปได้
พกพาได้ (Bourne และ POSIX):
(var=value; echo "1: $var"); echo "2: $var"
(... ) ด้านบนเริ่ม sub-shell (กระบวนการเชลล์ใหม่ในเชลล์ส่วนใหญ่) ดังนั้นตัวแปรใด ๆ ที่ประกาศว่าจะมีผลกับ sub-shell นั้นเท่านั้นดังนั้นฉันคาดว่าโค้ดด้านบนจะแสดงผลลัพธ์ "1: value" และ "2:" หรือ "2: what-var-was-set-to-before"
ด้วยเชลล์คล้ายบอร์นส่วนใหญ่คุณสามารถใช้ฟังก์ชั่นและบิวด์อิน "local":
f() {
local var
var=value
echo "1: $var"
}
f
echo "2: $var"
ด้วย zsh คุณสามารถใช้ฟังก์ชั่นอินไลน์:
(){ local var=value; echo "1: $var"; }; echo "2: $var"
หรือ:
function { local var=value; echo "1: $var"; }; echo "2: $var"
ด้วย bash และ zsh (แต่ไม่ใช่ ash, pdksh หรือ AT&T ksh) เคล็ดลับนี้ใช้งานได้:
var=value eval 'echo "1: $var"'; echo "2: $var"
ตัวแปรที่ทำงานในเปลือกหอยอีกไม่กี่ ( dash
, mksh
, yash
) แต่ไม่ได้zsh
(เว้นแต่ในsh
/ ksh
จำลอง):
var=value command eval 'echo "1: $var"'; echo "2: $var"
(ใช้command
ด้านหน้าบิวด์อินพิเศษ (ที่นี่eval
) ในเชลล์ POSIX ลบความพิเศษของพวกเขา (ที่นี่การกำหนดตัวแปรในจากพวกเขายังคงมีผลบังคับใช้หลังจากที่พวกเขากลับมา)
คุณกำลังทำมันอย่างถูกต้อง แต่ไวยากรณ์ของ bash นั้นตีความง่าย: คุณอาจคิดว่าecho $TEST
สาเหตุที่ทำให้เกิดecho
การเรียกTEST
env var จากนั้นพิมพ์มันไม่ได้ ได้รับดังนั้น
export TEST=123
แล้วก็
TEST=456 echo $TEST
เกี่ยวข้องกับลำดับต่อไปนี้:
เชลล์แยกวิเคราะห์บรรทัดคำสั่งทั้งหมดและดำเนินการแทนค่าตัวแปรทั้งหมดดังนั้นบรรทัดคำสั่งจะกลายเป็น
TEST=456 echo 123
มันสร้าง temp vars ที่ตั้งไว้ก่อนคำสั่งดังนั้นมันจะบันทึกค่าปัจจุบันของTEST
และแทนที่ด้วย 456; บรรทัดคำสั่งอยู่ในขณะนี้
echo 123
มันรันคำสั่งที่เหลือซึ่งในกรณีนี้พิมพ์ 123 เพื่อ stdout (ดังนั้นคำสั่งเชลล์ที่ยังคงไม่ได้ใช้แม้แต่ค่า temp ของTEST
)
มันคืนค่าของ TEST
ใช้ printenv แทนเนื่องจากไม่เกี่ยวข้องกับการทดแทนตัวแปร:
>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>
printenv
เป็นประโยชน์สำหรับการทดสอบพิสูจน์แนวคิด / (พฤติกรรมเช่นสคริปต์ไม่เมื่อเทียบกับecho
)
คุณสามารถทำงานนี้ได้โดยใช้:
TEST=foo && echo $TEST
TEST=foo
จะทำงานตามคำสั่งที่แยกจากกัน - echo
มันไม่ได้เป็นเพียงการตั้งค่าในบริบทของ