ตรงข้ามกับคำสั่ง `source '


9

ฉันใช้sourceคำสั่งในสคริปต์ทุบตีของฉันเพื่ออ่าน / พิมพ์ค่าตัวแปร

more linuxmachines_mount_point.txt

export linuxmachine01="sdb sdc sdf sdd sde sdg"
export linuxmachine02="sde sdd sdb sdf sdc"
export linuxmachine03="sdb sdd sdc sde sdf"
export linuxmachine06="sdb sde sdf sdd"

source  linuxmachines_mount_point.txt

echo $linuxmachine01
sdb sdc sdf sdd sde sdg

อะไรคือสิ่งที่ตรงกันข้ามsourceเพื่อยกเลิกการตั้งค่าตัวแปร?

ผลลัพธ์ที่คาดหวัง

echo $linuxmachine01

< no output >

14
มันไม่ได้sourceว่าคือการตั้งค่าตัวแปรในสภาพแวดล้อมของคุณ แต่งบในแฟ้มที่คุณexport sourceดังนั้นตรงข้ามของsourceอาจจะsourceถ้าคุณsourceเป็นไฟล์ที่แตกต่างกันซึ่งunsets ตัวแปรเหมือนกันทั้งหมด
user4556274

2
ใช่ไม่ใช้การส่งออกเพียงใช้ name = "val" การส่งออกมีไว้สำหรับตัวแปร script-to-binaries (สภาพแวดล้อม)
ctrl-d

1
ที่เกี่ยวข้อง: unix.stackexchange.com/q/382618/117549
Jeff Schaller

2
มันเป็นไปไม่ได้. แนวคิดที่คุณกำลังมองหาเรียกว่าคอมพิวเตอร์ที่พลิกกลับได้ ภาษาการเขียนโปรแกรมจำเป็นต้องได้รับการออกแบบโดยเฉพาะพร้อมข้อ จำกัด ที่รุนแรงบางอย่างเพื่อให้สามารถย้อนกลับได้ Bash ไม่ใช่ภาษาการเขียนโปรแกรมเหล่านั้น
Jörg W Mittag

1
@ Yael นั้นไม่เป็นความจริง (และคุณไม่เคยทดสอบเลยว่าคุณกำลังบอก ctrl-d ให้ทำ); คุณไม่จำเป็นต้องexportมี ทั้งหมดexportทำคือคัดลอกค่าลงในสภาพแวดล้อม - แต่มีอยู่เป็นตัวแปรเชลล์ไม่ว่าจะถูกกำหนดเป็นตัวแปรสภาพแวดล้อมหรือไม่ก็ตาม ยิ่งกว่านั้นการกำหนดตัวแปรสภาพแวดล้อมที่ไม่จำเป็นจะทำให้ความยาวบรรทัดคำสั่งสูงสุดสั้นลงเนื่องจากพวกมันถูกเก็บไว้ในพื้นที่ (จำกัด !) ต่อกระบวนการเดียวกัน
Charles Duffy

คำตอบ:


21

การใช้ subshell (แนะนำ)

เรียกใช้คำสั่ง source ในเชลล์ย่อย:

(
source linuxmachines_mount_point.txt
cmd1 $linuxmachine02
other_commands_using_variables
etc
)
echo $linuxmachine01  # Will return nothing

subshells จะถูกกำหนดโดย (...)parens: ตัวแปรเชลล์ใด ๆ ที่ตั้งค่าภายใน subshell จะถูกลืมเมื่อสิ้นสุด subshell

กำลังใช้งาน unset

สิ่งนี้จะยกเลิกตัวแปรที่ส่งออกโดยlinuxmachines_mount_point.txt:

unset $(awk -F'[ =]+' '/^export/{print $2}' linuxmachines_mount_point.txt)
  • -F'[ =]+' บอกให้ awk ใช้ช่องว่างและเครื่องหมายเท่ากับเป็นตัวคั่นฟิลด์

  • /^export/{print $2}

    สิ่งนี้บอก awk ให้เลือกบรรทัดที่ขึ้นต้นด้วยexportแล้วพิมพ์ฟิลด์ที่สอง

  • unset $(...)

    สิ่งนี้จะรันคำสั่งภายใน$(...)จับ stdout และยกเลิกตัวแปรใด ๆ ที่ตั้งชื่อโดยเอาต์พุต


ทำไมไม่ใช้สิ่งนี้ - สำหรับฉันในไฟล์ `awk '{print $ 2}' | awk -F "=" '{พิมพ์ $ 1}' `; อย่าตั้งค่า $ i; เสร็จแล้ว (ง่ายกว่าสำหรับการไม่ได้ตั้งค่า)
2560

2
@yael ใช้กระบวนการพิเศษและการวนซ้ำเมื่อไม่ต้องการ ความคิดเห็นอาจแตกต่างกัน แต่ฉันไม่เห็นว่าง่ายกว่า นอกจากนี้และอาจเป็นอันตรายก็ถือว่าทุกบรรทัดในfileเป็นคำสั่งการส่งออก
John1024

8
@yael นอกจากนี้การยกเลิกตัวแปรและการเลิกทำผลข้างเคียงของโค้ดอื่น ๆ นั้นเป็นสิ่งที่ subshells มีไว้ พวกเขาทำมันอย่างเรียบง่ายและน่าเชื่อถือ ยกเว้นในกรณีที่มีเหตุผลพิเศษมิฉะนั้น subshells คือสิ่งที่คุณควรใช้
John1024

4

คุณไม่สามารถยกเลิกsourceสคริปต์ได้

สิ่งที่คุณสามารถทำได้คือการจัดเก็บตัวแปรที่ส่งออกทั้งหมดในไฟล์ชั่วคราวเปรียบเทียบกับตัวแปรหลังจากที่สคริปต์มีแหล่งที่มาแล้วลบออกมากเกินไปด้วยunsetเช่น:

export > temp_file
source myscript

#... do some stuff

unset "$(comm -3 <(sort temp_file) <(export | sort) | awk -F'[ =]' '{print $3}' | tr '\n' ' ')"

ทำไมไม่ใช้สิ่งนี้ - สำหรับฉันในไฟล์ `awk '{print $ 2}' | awk -F "=" '{พิมพ์ $ 1}' `; อย่าตั้งค่า $ i; เสร็จแล้ว (ง่ายกว่าสำหรับการไม่ได้ตั้งค่า)
2560

@yael จะทำงานได้ก็ต่อเมื่อสคริปต์มีเพียงexports
jimmij

สิ่งที่คุณหมายถึง "การส่งออกของ" แฟ้มของฉันรวมถึง linuxmachine01 = "SDB SDC sdf SDD SDE SDG" และอื่น ๆ และเมื่อผมใช้วง awk ล้างตัวแปรของมันได้โดยไม่มีปัญหา
Yael

@yael ฉันไม่ทราบว่าไฟล์ของคุณมีลักษณะอย่างไรดังนั้นฉันจึงให้คำตอบทั่วไปตัวอย่างเช่นถ้าสคริปต์มีความคิดเห็นที่ด้านบนว่า "# นี่คือตัวแปรบางตัวที่จะส่งออกพร้อมจุดเมานท์"
jimmij

2

คุณสามารถใช้unsetคำสั่งเพื่อ "ลืม" ตัวแปร


ไฟล์อาจอยู่กับเครื่อง diff ดังนั้นวิธีการยกเลิกการตั้งค่าตัวแปรที่สองในไฟล์?
yael

การตั้งค่า variablename จะลืมมัน (คุณสามารถค้นหาได้อธิบายในหน้าตัวอย่าง bash / sh / ksh / zsh): pastebin.com/MGQyTZEA
francois P

ใช่ แต่เนื่องจากตัวแปรอาจแตกต่างกันสคริปต์ทุบตีต้องทำโดยอ่านตัวแปรจากไฟล์และยกเลิกการตั้งค่าจึงไม่คงที่เพราะตัวแปรไม่เป็นที่รู้จัก
yael

แล้วคุณ grep ส่งออกเส้น (ตัด) กับตัวแปรรายการจากไฟล์ที่จะส่งออก linuxmachine06 ล้าง = "SDB SDE sdf SDD" แล้วคุณจะได้รับ linuxmachine06 เป็นชื่อตัวอย่างล้าง A: pastebin.com/M9eCtLc7ที่คุณเห็นคำสั่งล้างที่นี่เดิ่น 'ทราบชื่อตัวแปรเป็นที่รู้จักกันเพียงปลาย
Francois P

ตกลงฉันจะใช้ไวยากรณ์นี้เพื่อยกเลิก - สำหรับฉันใน `awk '{พิมพ์ $ 2}' ไฟล์ | awk -F "=" '{พิมพ์ $ 1}' `; อย่าตั้งค่า $ i; เสร็จแล้ว
yael

2

ทางออกที่ง่ายที่สุดที่จะให้ผลลัพธ์ที่คุณคาดหวัง (ไม่มีอะไร) คือการประกาศตัวแปรอีกครั้งว่าว่างเปล่า:

$ export linuxmachine01="sdb sdc sdf sdd sde sdg"
$ echo "$linuxmachine01"
sdb sdc sdf sdd sde sdg

$ linuxmachine01=""
$ echo "$linuxmachine01"
$

แน่นอนว่าตัวแปรยังคงถูกกำหนด (และส่งออก), ว่างเปล่า แต่ถูกกำหนด:

$ declare -p linuxmachine01
declare -x linuxmachine01=""

หากต้องการลบตัวแปรอย่างถูกต้องทั้งจากสภาพแวดล้อมและเชลล์ที่กำลังรันอยู่คุณควรใช้ unset (วิธีที่แนะนำ):

$ unset linuxmachine01
$ declare -p linuxmachine01
bash: declare: linuxmachine01: not found
$ echo "$linuxmachine01"
$

1

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

export linuxmachine01="sdb sdc sdf sdd sde sdg"
export linuxmachine02="sde sdd sdb sdf sdc"
export linuxmachine03="sdb sdd sdc sde sdf"
export linuxmachine06="sdb sde sdf sdd"
alias linuxmachines_mount_point='for v in linuxmachine01 linuxmachine02 linuxmachine03 linuxmachine04; do unset $v; done; unalias linuxmachines_mount_point'

ทำไมนามแฝงมากกว่าฟังก์ชั่น? โปรดทราบว่านามแฝงถูกปิดใช้งานในเชลล์ที่ไม่มีการตอบโต้ตามค่าเริ่มต้นดังนั้นสิ่งนี้จะไม่ทำงานในสคริปต์
ชาร์ลส์ดัฟฟี่

... ที่จริงแล้วมันจะง่ายกว่านี้ถ้าเรานิยามตัวแปรเพียงตัวเดียวดังนั้นมันจึงมีเพียงอันเดียวที่จะยกเลิก: declare -A linuxmachines=( [01]="sdb sdc sdf" [02]="sde sdd sdb" [03]="whatever" )แล้วมันก็แค่unset linuxmachinesเปลี่ยนกลับไป
ชาร์ลส์ดัฟฟี่

@CharlesDuffy: ทั้งนามแฝงและฟังก์ชั่นใช้ได้สำหรับวัตถุประสงค์นี้ เหตุผลที่ฉันไม่แนะนำให้ใส่ทุกอย่างไว้ในตัวแปรเดียวคือการกำหนดคำสั่งเลิกทำเป็นเรื่องทั่วไป คุณสามารถยกเลิกการกำหนดไม่เพียง แต่ตัวแปร แต่ยังมีฟังก์ชั่น, นามแฝง, การตั้งค่าระบบ, การตั้งค่าเทอร์มินัล ฯลฯ มันให้สิ่งที่เป็นนามธรรมที่ดีกว่าเพราะคุณไม่ต้องสนใจเนื้อหาที่แน่นอนของคำสั่งเลิกทำ
Lie Ryan

ฉันเชื่อว่าประเด็นข้างต้นของฉันคือชื่อแทนไม่เหมาะสำหรับวัตถุประสงค์หาก "วัตถุประสงค์" รวมถึงการใช้แบบไม่โต้ตอบ (เช่นการเรียกใช้จากสคริปต์)
ชาร์ลส์ดัฟฟี่

0

คุณสามารถเขียน linuxmachines_mount_point.txt ของคุณเช่นนี้

test "$linuxmachine01" && unset -v linuxmachine01 || linuxmachine01="sdb sdc sdf sdd sde sdg"

เมื่อคุณต้องการตัวแปรของคุณ

source linuxmachines_mount_point.txt

เมื่อคุณต้องการลบตัวแปร

source linuxmachines_mount_point.txt

0

หากคุณกำลังใช้sourceคำสั่งเพื่อเปิดใช้งานคุณสามารถออกได้โดยใช้คำสั่งVirtualEnvironmentdeactivate

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