จะเริ่มต้นสคริปต์ด้วยสภาพแวดล้อมที่สะอาดได้อย่างไร


15

ฉันลองสิ่งต่อไปนี้ แต่ดูเหมือนจะไม่ทำงาน:

$ cat script.sh
#!/bin/env -i /bin/sh

/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.

พบคำถามที่คล้ายกัน แต่ไม่แสดงวิธีการทำจาก shebang: unix.stackexchange.com/questions/48994/…
balki

5
คุณไม่สามารถทำได้จาก shebang shebang สามารถยอมรับได้เพียงหนึ่ง ARG เท่านั้น
jordanm

คำตอบ:


7

ด้วยเหตุนี้ไม่ทำงานเป็นเพราะมันเห็นเป็นอาร์กิวเมนต์เดียวเพื่อ-i /bin/sh envนี้มักจะเป็น 2 ข้อโต้แย้งและ-i /bin/shนี่เป็นข้อ จำกัด ของ shebang ไม่มีทางรอบ ๆ มัน


อย่างไรก็ตามคุณยังสามารถทำงานนี้ได้ด้วยวิธีอื่น

หากคุณต้องการให้สคริปต์นี้ทำงานโดยไม่ต้องทำอะไรenv -i script.shคุณสามารถกำหนดให้สคริปต์ทำงานซ้ำได้

#!/bin/sh
[ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"

สิ่งนี้จะทำให้สคริปต์เรียกใช้งานตัวเองอีกครั้งหากCLEANEDไม่ได้ตั้งค่าตัวแปรสภาพแวดล้อม จากนั้นในการ re-exec มันตั้งค่าตัวแปรเพื่อให้แน่ใจว่ามันจะไม่เข้าไปในวง


envจาก coreutils ของ GNU ในขณะนี้มีตัวเลือก-Sในการแก้ไขปัญหาที่คล้ายคลึงกับอันนี้ แต่ไม่เหมือนกันทั้งหมด #!/usr/bin/env -S perl -Tเช่น
Weijun Zhou

เพิ่งลอง มันใช้งานได้สำหรับคำถามดั้งเดิมเช่นกัน #!/usr/bin/env -S -i /bin/shใช้เพียงแค่ ระวังปัญหาการพกพา
Weijun Zhou

3

เรียกใช้สคริปต์ของคุณด้วยenv -i:

env -i script.sh

และสคริปต์ตามปกติ:

#!/bin/sh
# ... your code here

หากคุณหมายถึงการทำงานด้วยสภาพแวดล้อมที่สะอาดโดยไม่ต้องพูดอย่างชัดเจนว่าเมื่อคุณเรียกใช้ Eduardo Ivanec ให้แนวคิดบางอย่างในคำตอบนี้คุณสามารถโทรหาสคริปต์ซ้ำด้วยexecเมื่อสภาพแวดล้อมไม่สะอาด (เช่นกำหนด $ HOME):

[ "$HOME" != "" ] && exec -c $0

ดี อย่าเพิ่งทำ env -i bash อย่างที่ฉันทำและสงสัยว่าทำไมตัวแปร env ของคุณยังคงถูกตั้งค่า (แน่นอนว่าทรัพยากร bash. bashrc และเพื่อน ๆ 8)
Neil McGill

2

ด้วย bash คุณสามารถทำสิ่งนี้ได้:

#!/usr/bin/bash

set -e
set -u

[ -v HOME ] && exec -c "$0" "$@"

# continue with the rest of the script
# e.g. print the cleaned environment:
export

set -eและset -u คำสั่งที่ไม่จำเป็นอย่างเคร่งครัด แต่ฉันรวมพวกเขาแสดงให้เห็นว่าวิธีนี้ไม่ได้พึ่งพาการเข้าถึงตัวแปร unset (เป็นเช่น[ "$HOME" != "" ]จะ) และเข้ากันได้กับset -eการตั้งค่า

การทดสอบHOMEตัวแปรควรมีความปลอดภัยเนื่องจาก bash จะเรียกใช้สคริปต์ในโหมดที่ไม่ต้องมีการโต้ตอบเช่นไฟล์การกำหนดค่าเช่น~/.bashrc(ซึ่งอาจมีการตั้งค่าตัวแปรสภาพแวดล้อม) ไม่ได้รับการจัดหาระหว่างการเริ่มต้น

ตัวอย่างผลลัพธ์:

declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"

0

$ cat script.sh

#!/bin/env -i /bin/sh

น่าเสียดายที่มันไม่ได้ผลเช่นนั้น - ลินุกซ์ถือว่า-i /bin/shเป็นอาร์กิวเมนต์เดียวที่จะถูกส่งผ่านไปยังenv(ดูShebang )


0

ข้อ จำกัด shebang Linux 2 ข้อโต้แย้ง (interpeter + อาร์กิวเมนต์เดี่ยว) ถูกระบุไว้ในคำตอบส่วนใหญ่ แต่การบอกว่าไม่สามารถทำได้ไม่ถูกต้อง - คุณเพียงแค่เปลี่ยนล่ามที่สามารถทำสิ่งที่มีประโยชน์กับอาร์กิวเมนต์เดียว:

#!/usr/bin/perl -we%ENV=();exec "/bin/sh " . join " ", map "'$_'", @ARGV;
# your sh script here

สิ่งนี้ทำคือเรียกใช้perlกับสคริปต์แบบหนึ่งซับ ( -e) ที่ล้าง%ENV(ราคาถูกกว่าenv -i) และเรียกใช้exec /bin/shโดยอ้างถึงข้อโต้แย้งอย่างถูกต้อง perlสามารถเพิ่มตรรกะเพิ่มเติมได้หากต้องการ (แม้ว่าจะมีไม่มากบน Linux เนื่องจากคุณ จำกัดBINPRM_BUF_SIZEอักขระที่อาจเป็น 128)

น่าเศร้านี่เป็นลินุกซ์ที่เฉพาะเจาะจงมันจะไม่ทำงานบนระบบที่อนุญาตให้มีการโต้แย้งหลาย Shebang: - /

perlประมวลผลสตริงนี้เป็นอาร์กิวเมนต์เดี่ยวดังนั้นจึงไม่ได้ยกมาข้างต้นตามที่คุณมักจะทำกับperl -e ...จากบรรทัดคำสั่ง (ถ้าคุณต้องการที่จะเพิ่มคำพูดเหล่านี้จะถูกเก็บไว้ Perl จะเห็นเพียงสตริงตัวอักษรด้วยคำเตือนจะบ่นเกี่ยวกับไร้ประโยชน์ คงที่)

โปรดทราบว่ามีการเปลี่ยนแปลงเล็กน้อยในพฤติกรรมเมื่อใช้วิธีนี้@ARGVโดยปกติมีเพียงอาร์กิวเมนต์และ$0มีสคริปต์ แต่ด้วย Shebang นี้$ARGV[0]เป็นชื่อของสคริปต์ (และ$0เป็น-e) ซึ่งทำให้ง่ายขึ้นเล็กน้อย

คุณสามารถแก้ปัญหานี้ได้ด้วยล่ามที่ "ประมวลผล" บรรทัดคำสั่ง (โดยไม่มี-cอาร์กิวเมนต์เพิ่มเติม) ที่ AT&T โบราณksh93ทำ:

#!/bin/ksh /usr/bin/env -i /bin/sh

แม้ว่าอาจkshจะไม่เหมือนกันทุกวันนี้ ;-)

( bashมีคุณสมบัติที่คล้ายกันด้วย--wordexp, แต่มันเป็น "ที่ไม่มีเอกสาร" ในรุ่นที่ทำงานและไม่เปิดใช้งานที่รวบรวมเวลาในรุ่นที่เป็นเอกสาร: - / นอกจากนี้ยังไม่สามารถนำมาใช้สำหรับการนี้เพราะมันต้องการสองข้อโต้แย้ง .. )

นอกจากนี้รูปแบบคำตอบของ @Patrick และ @ maxschlepzig ได้อย่างมีประสิทธิภาพ:

#!/bin/bash
[ "$_" != bash ] && exec -c -a "bash" /bin/bash "$0" "$@"
# your script here

แทนที่จะใช้ตัวแปรใหม่นี้จะใช้ตัวแปรพิเศษ " _" ถ้าไม่ได้ตั้งค่าเป็น "ทุบตี" อย่างแน่นอนจากนั้นแทนที่สคริปต์ด้วยการexecใช้-aเพื่อสร้างARGV[0](และด้วยเหตุนี้$_) เพียงแค่ "ทุบตี" และใช้-cเพื่อล้างสภาพแวดล้อม

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

#!/bin/sh
unset $(compgen -e)
# your script here

ที่ใช้compgen(ตัวช่วยเสร็จ) เพื่อแสดงรายการชื่อของตัวแปรสภาพแวดล้อมที่ส่งออกทั้งหมดและใช้unsetในครั้งเดียว

ดูเพิ่มเติมข้อโต้แย้งหลายรายการใน shebangสำหรับรายละเอียดเพิ่มเติมเกี่ยวกับปัญหาทั่วไปของพฤติกรรมของ shebang

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