ฉันลองสิ่งต่อไปนี้ แต่ดูเหมือนจะไม่ทำงาน:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
ฉันลองสิ่งต่อไปนี้ แต่ดูเหมือนจะไม่ทำงาน:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
คำตอบ:
ด้วยเหตุนี้ไม่ทำงานเป็นเพราะมันเห็นเป็นอาร์กิวเมนต์เดียวเพื่อ-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
เช่น
#!/usr/bin/env -S -i /bin/sh
ใช้เพียงแค่ ระวังปัญหาการพกพา
เรียกใช้สคริปต์ของคุณด้วยenv -i
:
env -i script.sh
และสคริปต์ตามปกติ:
#!/bin/sh
# ... your code here
หากคุณหมายถึงการทำงานด้วยสภาพแวดล้อมที่สะอาดโดยไม่ต้องพูดอย่างชัดเจนว่าเมื่อคุณเรียกใช้ Eduardo Ivanec ให้แนวคิดบางอย่างในคำตอบนี้คุณสามารถโทรหาสคริปต์ซ้ำด้วยexec
เมื่อสภาพแวดล้อมไม่สะอาด (เช่นกำหนด $ HOME):
[ "$HOME" != "" ] && exec -c $0
ด้วย 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"
$ cat script.sh
#!/bin/env -i /bin/sh
น่าเสียดายที่มันไม่ได้ผลเช่นนั้น - ลินุกซ์ถือว่า-i /bin/sh
เป็นอาร์กิวเมนต์เดียวที่จะถูกส่งผ่านไปยังenv
(ดูShebang )
ข้อ จำกัด 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