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.
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.
Jawaban:
Alasan ini tidak berhasil adalah karena ia melihat -i /bin/sh
sebagai argumen tunggal env
. Biasanya ini akan menjadi 2 argumen, -i
dan /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 CLEANED
variabel lingkungan tidak diatur. Kemudian pada re-exec, ia menetapkan variabel untuk memastikan bahwa itu tidak masuk ke loop.
env
dari GNU coreutils sekarang memiliki opsi -S
untuk menyelesaikan masalah yang mirip dengan yang satu ini tetapi tidak persis sama. Sebagai contoh #!/usr/bin/env -S perl -T
.
#!/usr/bin/env -S -i /bin/sh
. Waspadai masalah portabilitas.
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 exec
ketika lingkungan tidak bersih (mis. $ HOME didefinisikan):
[ "$HOME" != "" ] && exec -c $0
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 -e
dan 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 -e
pengaturan.
Pengujian HOME
variabel 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"
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 perl
dengan skrip satu baris ( -e
) yang menghapus %ENV
(lebih murah dari env -i
) dan memanggil exec /bin/sh
, dengan tepat mengutip argumen. perl
Logika 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: - /
perl
memproses 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, @ARGV
biasanya hanya berisi argumen, dan $0
berisi skrip, tetapi dengan shebang ini $ARGV[0]
adalah nama skrip (dan $0
sedang -e
) yang membuatnya sedikit lebih mudah.
Anda juga dapat menyelesaikan ini dengan penerjemah yang "memproses ulang" baris perintahnya (tanpa -c
argumen tambahan ) yang dilakukan oleh AT&T kuno ksh93
:
#!/bin/ksh /usr/bin/env -i /bin/sh
meskipun mungkin ksh
tidak biasa sekarang ;-)
( bash
memiliki 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 exec
menggunakan -a
untuk membuat ARGV[0]
(dan karenanya $_
) hanya "bash", dan gunakan -c
untuk 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 unset
s mereka dalam satu pergi.
Lihat juga Beberapa argumen di shebang untuk detail lebih lanjut tentang masalah umum perilaku shebang.