No Ubuntu 16.04.3, tenho um script bash muito simples:
test.sh
[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0
Quando eu o chamo como usuário não raiz me
ou como root
, ele funciona conforme o esperado. Se eu uso sudo ./test.sh
, ele reclama de um erro de sintaxe:
$ ./test.sh
true
me /bin/bash ./test.sh
$ sudo su
# ./test.sh
true
root /bin/bash ./test.sh
# exit
$ sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh
O que poderia estar causando isso? Como posso corrigi-lo para que me
possa usar este script normalmente e com sudo
?
Todo script começa com um Shebang , sem ele o shell que inicia seu script não sabe qual interpretador deve executar seu script 1 e pode - como no caso
sudo ./script.sh
daqui - executá-lo comsh
, que no Ubuntu 16.04 está vinculado adash
. A expressão condicional[[
é umbash
comando composto , entãodash
não sabe como lidar com isso e gera o erro que você encontrou.A solução aqui é adicionar
como a primeira linha do seu script. Você pode obter o mesmo resultado ao chamá-lo explicitamente com
sudo bash ./script.sh
, mas um shebang é o caminho a percorrer.Para verificar qual shell executa seu script, adicione
echo $0
a ele. Isso não é o mesmo queecho $SHELL
, citando wiki.archlinux.org :1: Como você começou
./test.sh
combash
apenas assumiubash
, o mesmo vale para osudo su
subshell.Como @dessert explicou , o problema aqui é que seu script não tem uma linha shebang . Sem um shebang,
sudo
o padrão será tentar executar o arquivo usando/bin/sh
. Não consegui encontrar documentado em lugar nenhum, mas confirmei verificando osudo
código fonte onde encontrei o seguinte no arquivopathnames.h
:Isso significa "definir se a variável
_PATH_BSHELL
não estiver definida, defina-a como/bin/sh
". Então, noconfigure
script incluído no tarball fonte, temos:Este loop procurará
/bin/bash
,/usr/bin/sh
, ou/sbin/sh
e então definirá o que for encontrado primeiro . Como era o primeiro da lista e existe, é definido como . O resultado de tudo isso é que o shell padrão de , a menos que definido de outra forma, seja ./usr/sbin/sh
/bin/ksh
_PATH_BSHELL
/bin/sh
_PATH_BSHELL
/bin/sh
sudo
/bin/sh
Portanto,
sudo
o padrão será executar as coisas usando/bin/sh
e, no Ubuntu, um link simbólico paradash
, um shell mínimo compatível com POSIX:A
[[
construção é um recurso bash, não é definida pelo padrão POSIX e não é compreendida pordash
:Em detalhes, nas três invocações que você tentou:
./test.sh
Não
sudo
; na ausência de uma linha shebang, seu shell tentará executar o próprio arquivo. Como você está executando obash
, isso será executadobash ./test.sh
e funcionará efetivamente.sudo su
seguido por./test.sh
.Aqui, você está iniciando um novo shell para o usuário
root
. Este será o shell definido na$SHELL
variável de ambiente para esse usuário e, no Ubuntu, o shell padrão do root ébash
:sudo ./test.sh
Aqui, você está deixando
sudo
executar o comando diretamente. Como seu shell padrão é/bin/sh
explicado acima, isso faz com que ele execute o script com/bin/sh
, que édash
e falha, poisdash
não entende[[
.Nota : os detalhes de como
sudo
define o shell padrão parecem ser um pouco mais complexos. Tentei alterar os arquivos mencionados em minha resposta para apontar,/bin/bash
massudo
ainda estava com o padrão/bin/sh
. Portanto, deve haver alguns outros locais no código-fonte onde o shell padrão é definido. No entanto, o ponto principal (quesudo
é padronizado parash
) ainda permanece.