ยกเลิกการตั้งค่าตัวแปรสภาพแวดล้อมสำหรับหนึ่งคำสั่ง


24

ฉันสามารถเรียกใช้ENV_VAR=value commandเพื่อให้ทำงานที่มีค่าเฉพาะสำหรับcommand ENV_VARอะไรที่เทียบเท่ากับ unset ENV_VARสำหรับcommand?


7
นอกเหนือ: commandเป็นทางเลือกที่โชคร้ายของตัวยึดเนื่องจากมีจริงคือในตัวคำสั่งโดยใช้ชื่อที่ mycommandหรือsomecommandอาจจะเป็นนิสัยที่ดีกว่าในการเข้ามา
ชาร์ลส์ดัฟฟี่

@CharlesDuffy ฉันมักจะใช้cmdสำหรับการที่
Stéphane Chazelas

คำตอบ:


35

นอกเหนือจาก-iตัวเลือกซึ่งใช้envล้างสภาพแวดล้อมทั้งหมด POSIX ไม่มีวิธีการยกเลิกการตั้งค่าตัวแปร

อย่างไรก็ตามด้วยการenvใช้งานบางอย่าง(รวมถึง GNU, busybox'และ FreeBSD เป็นอย่างน้อย) คุณสามารถทำได้:

env -u ENV_VAR command

ซึ่งจะทำงานในการลบทุกอินสแตนซ์ของENV_VARตัวแปรจากสภาพแวดล้อม (โปรดทราบว่ามันไม่ทำงานสำหรับตัวแปรสภาพแวดล้อมที่มีชื่อว่างเปล่า ( env -u ''อาจให้ข้อผิดพลาดหรือไม่มีประสิทธิภาพขึ้นอยู่กับการนำไปใช้แม้ว่าจะยอมรับทั้งหมดenv '=value'อาจเป็นข้อ จำกัด ที่เกิดขึ้นจากunsetenv()ฟังก์ชั่น C ซึ่ง POSIX ต้องการส่งคืนข้อผิดพลาดสำหรับสตริงว่างขณะที่ไม่มีข้อ จำกัด ดังกล่าวputenv()))

พกพาได้ (ใน POSIX shells) คุณสามารถทำสิ่งต่อไปนี้

(unset -v ENV_VAR; exec command)

(โปรดทราบว่าในบางเชลล์การใช้execสามารถเปลี่ยนสิ่งที่commandรันได้: รันหนึ่งในระบบไฟล์แทนฟังก์ชั่นหรือ builtin เช่น (และจะหลีกเลี่ยงaliasการขยายตัวที่เห็นได้ชัด) เช่นenvด้านบนคุณต้องการละเว้นในกรณีเหล่านี้) .

แต่นั่นจะไม่ทำงานสำหรับตัวแปรสภาพแวดล้อมที่มีชื่อที่ไม่สามารถแมปกับตัวแปรเชลล์ได้ (โปรดทราบว่าบางเชลล์ที่ชอบmkshจะตัดตัวแปรเหล่านั้นออกจากสภาพแวดล้อมเมื่อเริ่มต้นอย่างไรก็ตาม) หรือตัวแปรที่ทำเครื่องหมายว่าเป็นแบบอ่านอย่างเดียว

-vใช้สำหรับเชลล์เป้าหมายและbashผู้ที่unsetไม่-vสามารถยกเลิกการตั้งค่าENV_VAR ฟังก์ชั่นหากไม่มีตัวแปรตามชื่อนั้น เชลล์อื่น ๆ ส่วนใหญ่จะไม่ตั้งค่าฟังก์ชั่นจนกว่าคุณจะผ่าน-fตัวเลือก (ไม่น่าจะสร้างความแตกต่างในทางปฏิบัติ)

(นอกจากนี้ระวังข้อผิดพลาด / misfeature ของbash/ mksh/ yashซึ่งunsetภายใต้สถานการณ์บางอย่างอาจไม่ล้างค่าตัวแปร แต่เปิดเผยตัวแปรในขอบเขตด้านนอก )

ถ้าperlมีคุณสามารถทำได้:

perl -e 'delete $ENV{shift@ARGV}; exec @ARGV or die$!' ENV_VAR command

ซึ่งจะทำงานได้แม้กับตัวแปรสภาพแวดล้อมที่มีชื่อว่าง

ตอนนี้สิ่งเหล่านั้นจะไม่ทำงานหากคุณต้องการเปลี่ยนตัวแปรสภาพแวดล้อมสำหรับ builtin หรือฟังก์ชั่นและไม่ต้องการให้พวกเขาทำงานใน subshell เช่นในbash:

env -u LANG printf -v var %.3f 1.2 # would run /usr/bin/printf instead
(unset -v LANG; printf -v var %.3f 1.2) # changes to $var lost afterwards

(ที่นี่ unsetting LANG เป็นวิธีการที่ผิดที่ทำให้แน่ใจว่า.จะใช้และเข้าใจเป็นตัวคั่นทศนิยม. มันจะดีกว่าที่จะใช้LC_ALL=C printf...สำหรับที่)

ด้วยเชลล์บางตัวคุณสามารถสร้างขอบเขตโลคัลสำหรับตัวแปรโดยใช้ฟังก์ชัน:

without() {
  local "$1" # $1 variable declared as initially unset in bash¹
  shift
  "$@"
}
without LANG printf -v var %.3f 1.2

ด้วยzsh, คุณยังสามารถใช้ฟังก์ชันที่ไม่ระบุชื่อ:

(){local ENV_VAR; command}

วิธีการนั้นจะไม่ทำงานในเชลล์บางตัว (เช่นเดียวกับที่ใช้เชลล์ Almquist) ซึ่งlocalไม่ได้ประกาศตัวแปรว่าเริ่มแรกแล้ว (แต่สืบทอดค่าและคุณสมบัติ) ในสิ่งเหล่านั้นคุณสามารถทำได้local ENV_VAR; unset ENV_VARแต่อย่าทำอย่างนั้นในmkshหรือyash( typesetแทนที่จะlocalเป็นแบบนั้น) เพราะวิธีนี้ใช้ไม่ได้ผลunsetจะเป็นการยกเลิกlocalเท่านั้น

¹ระวังด้วยว่าในbashนั้นโลคัลENV_VAR(แม้ว่าจะไม่ได้ตั้งค่า) จะเก็บแอตทริบิวต์ส่งออกไว้ ดังนั้นถ้าcommandเป็นฟังก์ชันที่กำหนดค่าให้ENV_VARตัวแปรจะพร้อมใช้งานในสภาพแวดล้อมของคำสั่งที่เรียกว่าหลังจากนั้น unset ENV_VARจะล้างแอตทริบิวต์นั้น หรือคุณสามารถใช้local +x ENV_VARซึ่งจะให้แน่ใจว่ากระดานชนวนสะอาด (ยกเว้นว่าตัวแปรที่ได้รับการประกาศให้อ่านอย่างเดียว แต่แล้วไม่มีอะไรที่คุณสามารถทำได้เกี่ยวกับมันbash)


1
มันเป็นคำถามที่แยกต่างหาก แต่สิ่งที่ heck คือตัวแปรสภาพแวดล้อมที่มีชื่อว่างเปล่าและคุณจะใช้มันอย่างไร - แม้จะเป็นการหาประโยชน์บางอย่าง? คุณไม่ต้องเขียนโปรแกรมที่อ่านสภาพแวดล้อมและมองหาสิ่งนี้โดยเฉพาะหรือไม่?
Joe

@ Joe env '=foo' python -c 'import os; print os.environ[""]'ลองยกตัวอย่างเช่น ฉันไม่คาดหวังว่าหลายคนจะต้องการตั้งค่าตัวแปรแบบนั้น
Stéphane Chazelas

9

ไม่มีอะไรเทียบเท่าโดยตรงเท่าที่ฉันรู้ คุณสามารถใช้เชลล์ย่อย:

(unset ENV_VAR; exec command)

(unset ENV_VAR; exec somecommand)ถ้าคุณต้องการที่จะเทียบเท่ากับต้นฉบับในประสิทธิภาพ (โดยการบริโภค subshell) ตามที่เป็นอยู่นี้จะเพิ่มทางแยกพิเศษ
ชาร์ลส์ดัฟฟี่

1
@Charles แน่นอนแม้ว่าบางเชลล์ทำโดยอัตโนมัติเนื่องจากcommandเป็นคำสั่งสุดท้ายในการเรียกใช้ subshell
Stephen Kitt

+1 เนื่องจากวิธีนี้ง่ายต่อการพิมพ์สำหรับการใช้แบบโต้ตอบ ผมใช้ subshells สำหรับ one-off env -uเปลี่ยนแปลงสภาพแวดล้อมเปลือกสำหรับหนึ่งซับแทนการจดจำว่ามันเป็น
ปีเตอร์กอร์เดส

0

คุณสามารถใช้ได้ ENV_VAR= command

นี่ไม่ได้ทำการยกเลิกการตั้งค่าตัวแปร แต่อาจมีประโยชน์ในหลายกรณี (โดยปกติเชลล์สคริปต์จะใช้test -nเพื่อตรวจสอบว่ามีการตั้งค่าตัวแปร) หรือไม่:

$ export ENV_VAR=foo
$ mycommand
ENV_VAR: foo
$ ENV_VAR=bar mycommand
ENV_VAR: bar
$ ENV_VAR= mycommand
ENV_VAR: 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.