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 usar 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 esse script normalmente e com sudo
?
sudo su
. Basta executarsudo -i
ou emsudo -s
vez disso.sudo -i
altera a localização para/root
.sudo su
ousudo -s
não altere o local do diretório.-s
.Respostas:
Todo script começa com um Shebang , sem ele, o shell que inicia o script não sabe qual intérprete deve executar o seu script 1 e pode - como no caso
sudo ./script.sh
aqui - executá-losh
, ao qual o Ubuntu 16.04 está vinculadodash
. A expressão condicional[[
é umbash
comando composto , portantodash
, não sabe como lidar com isso e lança o erro que você encontrou.A solução aqui é adicionar
como a primeira linha do seu script. Você pode obter o mesmo resultado quando o chama explicitamente
sudo bash ./script.sh
, mas um shebang é o caminho a percorrer.Para verificar qual shell executa seu script, adicione
echo $0
-o. Não é o mesmo queecho $SHELL
, citando wiki.archlinux.org :1: Como você começou
./test.sh
combash
ele apenas assumiubash
, o mesmo vale para osudo su
subnível.fonte
/bin/sh
.echo $0
Dá-me o nome do script:./test.sh
)/proc/$$/exe
. Além disso, você pode testar várias variáveis como$BASH_VERSION
,$ZSH_VERSION
, etc. (mas traço não define qualquer variável)Como o @dessert explicou , o problema aqui é que seu script não tem uma linha shebang . Sem um shebang,
sudo
o padrão é tentar executar o arquivo usando/bin/sh
. Não consegui encontrá-lo documentado em nenhum lugar, 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 de origem, temos:Este circuito irá procurar
/bin/bash
,/usr/bin/sh
,/sbin/sh
,/usr/sbin/sh
ou/bin/ksh
e, em seguida, define o_PATH_BSHELL
que o que foi encontrado pela primeira vez . Como/bin/sh
foi o primeiro na lista e existe,_PATH_BSHELL
está definido como/bin/sh
. O resultado de tudo isso é que o shell padrão, asudo
menos que seja definido de outra forma, é/bin/sh
.Portanto,
sudo
o padrão será executar as coisas usando/bin/sh
e, no Ubuntu, que é um link simbólico paradash
, um mínimo de shell compatível com POSIX:A
[[
construção é um recurso bash, não é definido pelo padrão POSIX e não é entendido 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á executandobash
, isso funcionarábash ./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
como explicado acima, isso faz com que ele execute o script/bin/sh
, o que édash
e falha desde quedash
ele não entende[[
.Nota : os detalhes de como
sudo
define o shell padrão parecem um pouco mais complexos. Tentei alterar os arquivos mencionados na minha resposta para apontar para,/bin/bash
massudo
ainda era o padrão/bin/sh
. Portanto, deve haver outros lugares no código-fonte em que o shell padrão está definido. No entanto, o ponto principal (que osudo
padrão ésh
) ainda permanece.fonte
/bin/sh
partir da mensagem de erro - o que mais poderia ser possível? A pergunta é respondida lindamente em Qual shell o sudo usa · SO , consulte também aman sudo
seção COMMAND EXECUTION . Acontecesudo
que não usa um shell intermediário !execve
chamada de sistema à qual o padrão ésh
. E não, shells intermediários são irrelevantes, não se trata do shell que executa o comando, mas do interpretador de shell usado para ler o script de shell fornecido. Portanto, não, ele não inicia um shell intermediário, mas ainda precisa de um interpretador de shell para scripts de shell.