web-dev-qa-db-fra.com

script bash: résultats différents quand on appelle avec ou sans sudo

Dans Ubuntu 16.04.3, j'ai un script bash très simple:

test.sh

[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $Shell $0

Lorsque je l'appelle en tant qu'utilisateur non root meou en tant que rootname__, cela fonctionne comme prévu. Si j'utilise Sudo ./test.sh, il se plaint d'une erreur de syntaxe:

$ ./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

Qu'est-ce qui peut causer cela? Comment puis-je résoudre le problème de sorte que mepuisse utiliser ce script à la fois normalement et avec Sudoname__?

10
James Newton

Comme @ dessert expliqué , le problème ici est que votre script n'a pas de ligne Shebang . Sans Shebang, Sudotentera par défaut d'exécuter le fichier à l'aide de /bin/sh. Je ne pouvais pas le trouver documenté nulle part, mais j'ai confirmé en vérifiant le code source Sudooù j'ai trouvé ce qui suit dans le fichier pathnames.h:

#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif /* _PATH_BSHELL */

Cela signifie "défini si la variable _PATH_BSHELL n'est pas définie, définissez-la sur /bin/sh". Ensuite, dans le script configureinclus dans l’archive source, nous avons:

for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do
    if test -f "$p"; then
    found=yes
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5
$as_echo "$p" >&6; }
    cat >>confdefs.h <<EOF
#define _PATH_BSHELL "$p"
EOF

    break
    fi
done

Cette boucle recherchera /bin/bash, /usr/bin/sh, /sbin/sh, /usr/sbin/sh ou /bin/ksh et définira ensuite le _PATH_BSHELL sur selon celui trouvé en premier . Étant donné que /bin/sh était le premier de la liste et qu'elle existe, _PATH_BSHELL est défini sur /bin/sh. Le résultat de tout cela est que le shell par défaut de Sudoname__, sauf indication contraire, est /bin/sh.

Donc, Sudoutilisera par défaut /bin/sh et, sous Ubuntu, un lien symbolique vers dashname__, un shell minimal compatible POSIX:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 27  2015 /bin/sh -> dash

La construction [[ est une fonctionnalité bash, elle n'est pas définie par le standard POSIX et n'est pas comprise par dashname__:

$ bash -c '[[ true ]] && echo yes'
yes
$ dash -c '[[ true ]] && echo yes'
dash: 1: [[: not found

En détail, dans les trois invocations que vous avez essayées:

  1. ./test.sh

    Non Sudoname__; En l'absence d'une ligne Shebang, votre shell tentera d'exécuter le fichier lui-même. Puisque vous exécutez bashname__, ceci exécutera effectivement bash ./test.sh et fonctionnera.

  2. Sudo su suivi de ./test.sh.

    Ici, vous démarrez un nouveau shell pour l'utilisateur rootname__. Ce sera ce que Shell sera défini dans la variable d'environnement $Shell pour cet utilisateur et, sous Ubuntu, le shell par défaut de la racine sera bashname__:

    $ grep root /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    
  3. Sudo ./test.sh

    Ici, vous laissez Sudoexécuter directement la commande. Comme son shell par défaut est /bin/sh comme expliqué ci-dessus, le script est alors exécuté avec /bin/sh, qui est dashet échoue car dashne comprend pas [[.


Remarque : les détails de la manière dont Sudodéfinit le shell par défaut semblent un peu plus complexes. J'ai essayé de changer les fichiers mentionnés dans ma réponse pour qu'ils pointent vers /bin/bash mais Sudoétait toujours par défaut à /bin/sh. Il doit donc y avoir d'autres endroits dans le code source où le shell par défaut est défini. Néanmoins, le point principal (Sudopar défaut à shname__) est toujours valable.

5
terdon