Bagaimana cara memulai skrip dengan lingkungan bersih?

15

Saya mencoba yang berikut tetapi sepertinya tidak berhasil:

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

/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
balki
sumber
Menemukan pertanyaan serupa tetapi tidak menunjukkan bagaimana melakukannya dari shebang: unix.stackexchange.com/questions/48994/…
balki
5
Anda tidak dapat melakukannya dari shebang. Shebang hanya dapat menerima satu arg.
jordanm

Jawaban:

7

Alasan ini tidak berhasil adalah karena ia melihat -i /bin/shsebagai argumen tunggal env. Biasanya ini akan menjadi 2 argumen, -idan /bin/sh. Ini hanyalah batasan dari shebang. Tidak ada jalan lain.


Namun Anda masih dapat melakukan tugas ini, hanya dengan cara yang berbeda.

Jika Anda ingin tugas ini dilakukan oleh skrip itu sendiri, dan tidak harus melakukan sesuatu seperti env -i script.sh, Anda dapat meminta skrip dijalankan kembali.

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

Ini akan menyebabkan skrip untuk mengeksekusi ulang dirinya sendiri jika CLEANEDvariabel lingkungan tidak diatur. Kemudian pada re-exec, ia menetapkan variabel untuk memastikan bahwa itu tidak masuk ke loop.

Patrick
sumber
envdari GNU coreutils sekarang memiliki opsi -Suntuk menyelesaikan masalah yang mirip dengan yang satu ini tetapi tidak persis sama. Sebagai contoh #!/usr/bin/env -S perl -T.
Weijun Zhou
Baru mencoba. Ini berfungsi untuk pertanyaan asli juga. Gunakan saja #!/usr/bin/env -S -i /bin/sh. Waspadai masalah portabilitas.
Weijun Zhou
3

Jalankan skrip Anda dengan env -i :

env -i script.sh

Dan skrip seperti biasa:

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

Jika Anda bermaksud untuk menjalankan dengan lingkungan yang bersih tanpa secara eksplisit mengatakan bahwa ketika Anda menjalankan. Eduardo Ivanec memberikan beberapa ide dalam jawaban ini , Anda dapat memanggil skrip Anda secara rekursif execketika lingkungan tidak bersih (mis. $ HOME didefinisikan):

[ "$HOME" != "" ] && exec -c $0
RSFalcon7
sumber
Bagus. Hanya saja jangan lakukan env-i bash seperti yang saya lakukan dan kemudian bertanya-tanya mengapa variabel env Anda masih ditetapkan (tentu saja sumber daya bash .bashrc dan teman-teman 8)
Neil McGill
2

Dengan bash, Anda dapat melakukannya seperti ini:

#!/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

The set -edan set -u perintah tidak benar-benar diperlukan, tapi saya termasuk mereka untuk menunjukkan bahwa pendekatan ini tidak bergantung pada mengakses variabel unset (sebagai misalnya [ "$HOME" != "" ]akan) dan kompatibel dengan set -epengaturan.

Pengujian HOMEvariabel harus aman karena bash mengeksekusi skrip dalam mode non-interaktif, yaitu file konfigurasi seperti ~/.bashrc(di mana variabel lingkungan dapat diatur) tidak bersumber selama startup.

Contoh output:

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

$ cat script.sh

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

Sayangnya itu tidak akan bekerja seperti itu - Linux menganggap -i /bin/shsebagai satu argumen untuk diteruskan ke env(lihat Shebang ).

poige
sumber
0

Batasan shebang 2-argumen Linux (interpeter + argumen tunggal) dicatat di sebagian besar jawaban, tetapi untuk mengatakan ini tidak dapat dilakukan adalah salah - Anda hanya perlu mengubah ke penerjemah yang dapat melakukan sesuatu yang berguna dengan satu argumen:

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

Apa yang dilakukan adalah dipanggil perldengan skrip satu baris ( -e) yang menghapus %ENV(lebih murah dari env -i) dan memanggil exec /bin/sh, dengan tepat mengutip argumen. perlLogika lebih lanjut dapat ditambahkan, jika diperlukan (meskipun tidak banyak di Linux karena Anda terbatasBINPRM_BUF_SIZE karakter, yang kemungkinan 128)

Sayangnya, ini adalah Linux khusus, ini tidak akan bekerja pada sistem yang memungkinkan beberapa argumen shebang: - /

perlmemproses string ini sebagai argumen tunggal, jadi itu tidak dikutip di atas seperti yang biasa Anda lakukan dengan perl -e ...dari baris perintah (jika Anda menambahkan tanda kutip ini dipertahankan, perl melihat hanya string literal, dengan peringatan di atasnya akan mengeluh tentang tidak berguna konstan).

Juga perhatikan ada sedikit perubahan dalam perilaku ketika digunakan dengan cara ini, @ARGVbiasanya hanya berisi argumen, dan $0berisi skrip, tetapi dengan shebang ini $ARGV[0]adalah nama skrip (dan $0sedang -e) yang membuatnya sedikit lebih mudah.

Anda juga dapat menyelesaikan ini dengan penerjemah yang "memproses ulang" baris perintahnya (tanpa -cargumen tambahan ) yang dilakukan oleh AT&T kuno ksh93:

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

meskipun mungkin kshtidak biasa sekarang ;-)

( bashmemiliki fitur serupa dengan --wordexp, tetapi "tidak terdokumentasi" dalam versi di mana ia bekerja, dan tidak diaktifkan pada waktu kompilasi dalam versi yang didokumentasikan: - / Ini juga tidak dapat digunakan untuk ini karena memerlukan dua argumen. ..)

Juga, secara efektif variasi jawaban @Patrick dan @ maxschlepzig:

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

Daripada menggunakan variabel baru, ini menggunakan " _" variabel khusus, jika tidak disetel persis "bash" kemudian ganti skrip dengan execmenggunakan -auntuk membuat ARGV[0](dan karenanya $_) hanya "bash", dan gunakan -cuntuk membersihkan lingkungan.

Atau, jika dapat diterima untuk membersihkan lingkungan di awal skrip (hanya bash):

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

Itu menggunakan compgen(pembantu penyelesaian) untuk mendaftar nama-nama semua variabel lingkungan yang diekspor, dan unsets mereka dalam satu pergi.

Lihat juga Beberapa argumen di shebang untuk detail lebih lanjut tentang masalah umum perilaku shebang.

mr.spuratic
sumber