ถ้าฉันวิ่ง
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การเรียกTESTenv 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มันไม่ได้เป็นเพียงการตั้งค่าในบริบทของ