Ho provato quanto segue ma non sembra funzionare:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Ho provato quanto segue ma non sembra funzionare:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Risposte:
Il motivo per cui non funziona è perché vede -i /bin/sh
come un unico argomento env
. Di solito questo sarebbe 2 argomenti -i
e /bin/sh
. Questa è solo una limitazione dello shebang. Assolutamente no.
Tuttavia è ancora possibile eseguire questa attività, solo in un modo diverso.
Se si desidera che questa attività venga eseguita dallo script stesso e non si debba fare qualcosa del genere env -i script.sh
, è possibile ripetere l'esecuzione dello script.
#!/bin/sh
[ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"
Ciò causerà la riesecuzione automatica dello script se la CLEANED
variabile di ambiente non è impostata. Quindi su re-exec, imposta la variabile per assicurarsi che non entri in un ciclo.
env
dai coreutils GNU ora hanno un'opzione -S
per risolvere i problemi simili a questo ma non esattamente lo stesso. Per esempio #!/usr/bin/env -S perl -T
.
#!/usr/bin/env -S -i /bin/sh
. Essere consapevoli dei problemi di portabilità.
Esegui il tuo script con env -i
:
env -i script.sh
E la sceneggiatura come al solito:
#!/bin/sh
# ... your code here
Se intendi correre con un ambiente pulito senza dirlo esplicitamente quando corri. Eduardo Ivanec dà alcune idee in questa risposta , puoi chiamare ricorsivamente il tuo script con exec
quando l'ambiente non è pulito (ad esempio $ HOME è definito):
[ "$HOME" != "" ] && exec -c $0
Con bash, puoi farlo in questo modo:
#!/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
I comandi set -e
e set -u
non sono strettamente necessari, ma li includo per dimostrare che questo approccio non si basa sull'accesso a variabili non impostate (come ad esempio [ "$HOME" != "" ]
farebbe) ed è compatibile con set -e
un'impostazione.
Il test della HOME
variabile dovrebbe essere sicuro perché bash esegue gli script in modalità non interattiva, vale a dire che i file di configurazione come ~/.bashrc
(dove è possibile impostare le variabili di ambiente) non provengono durante l'avvio.
Esempio di output:
declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"
La limitazione shebang di Linux a 2 argomenti (interpeter + singolo argomento) è annotata nella maggior parte delle risposte, ma dire che ciò non può essere fatto è errato - devi solo passare a un interprete che può fare qualcosa di utile con un singolo argomento:
#!/usr/bin/perl -we%ENV=();exec "/bin/sh " . join " ", map "'$_'", @ARGV;
# your sh script here
Ciò che fa ciò è invocare perl
con uno script one-liner ( -e
) che cancella %ENV
(più economico di env -i
) e invoca exec /bin/sh
, citando correttamente gli argomenti. È perl
possibile aggiungere ulteriore logica, se necessario (anche se non molto su Linux poiché sei limitato ai BINPRM_BUF_SIZE
caratteri, che è probabilmente 128)
Purtroppo, questo è specifico di Linux, non funzionerà su un sistema che consente molteplici argomenti shebang: - /
perl
elabora questa stringa come un singolo argomento, quindi non è citata sopra come faresti normalmente perl -e ...
dalla riga di comando (se dovessi aggiungere virgolette queste vengono conservate, perl vede solo una stringa letterale, con avvisi su di essa si lamenterà di un inutile costante).
Nota anche che c'è un leggero cambiamento nel comportamento quando usato in questo modo, @ARGV
normalmente contiene solo gli argomenti e $0
contiene lo script, ma con questo shebang $ARGV[0]
è il nome dello script (ed $0
è -e
) che lo rende un po 'più facile.
Puoi anche risolverlo con un interprete che "rielabora" la sua riga di comando (senza un -c
argomento in più) che l'antica AT&T ksh93
fa:
#!/bin/ksh /usr/bin/env -i /bin/sh
anche se forse ksh
non è così comune al giorno d'oggi ;-)
( bash
ha una funzione simile con --wordexp
, ma è "non documentato" nelle versioni in cui funziona e non è abilitato in fase di compilazione nelle versioni in cui è documentato: - / Inoltre non può essere utilizzato per questo poiché ha bisogno di due argomenti. ..)
Inoltre, effettivamente una variazione sulle risposte di @Patrick e @ maxschlepzig:
#!/bin/bash
[ "$_" != bash ] && exec -c -a "bash" /bin/bash "$0" "$@"
# your script here
Invece di usare una nuova variabile, questa utilizza la speciale " _
" variabile, se non è impostata esattamente su "bash", quindi sostituire lo script con l' exec
utilizzo -a
di make ARGV[0]
(e quindi $_
) solo "bash" e l'utilizzo -c
per cancellare l'ambiente.
In alternativa, se è accettabile pulire l'ambiente all'inizio dello script (solo bash):
#!/bin/sh
unset $(compgen -e)
# your script here
Questo usa compgen
(helper di completamento) per elencare i nomi di tutte le variabili d'ambiente esportate e le usa unset
in una volta sola.
Vedi anche Argomenti multipli in shebang per maggiori dettagli sul problema generale del comportamento di shebang.