GNU/Linux >> Tutoriels Linux >  >> Linux

Pourquoi le parent Shell Here-document ne fonctionne pas pour la sous-commande dans Dash mais Bash fonctionne?

Je suis exécuté sur debian stretch, toutes les commandes ci-dessous (dash et bash ) est entré dans bash.
Le whoami semble ne jamais fonctionner en tant qu'utilisateur test en tiret comme dans les codes ci-dessous.

$ sudo dash << 'end'
> su test
> whoami
> end
root
$ sudo bash << 'end'
> su test
> whoami
> end
test

Réponse acceptée :

Considérez plutôt cet exemple :

$ cat f
grep pos /proc/self/fdinfo/0
IFS= read -r var
echo A
echo B
printf '%s\n' "var=$var"
$ bash < f
pos:    29
B
var=echo A
$ dash < f
pos:    85
A
B
var=

Comme vous pouvez le voir, à l'époque le grep la commande est exécutée, la position dans stdin est à la fin du fichier avec dash , et juste après la nouvelle ligne qui suit le grep commande dans bash .

Le echo A la commande est exécutée par dash mais dans le cas de bash , il est alimenté en entrée pour read .

Ce qui s'est passé, c'est ce dash lire toute l'entrée (en fait, un bloc de texte) pendant que bash lisez une ligne à la fois avant d'exécuter des commandes.

Pour ce faire, bash aurait besoin de lire un octet à la fois pour s'assurer qu'il ne lit pas au-delà de la nouvelle ligne, mais lorsque l'entrée est un fichier normal (comme dans le cas de mon f fichier ci-dessus, mais aussi pour les documents ici que bash implémente en tant que fichiers temporaires, tandis que dash utilise des pipes), bash l'optimise en lisant par blocs et en revenant à la fin de la ligne, ce que vous pouvez voir avec strace sous Linux :

$ strace -e read,lseek bash < f
[...]
lseek(0, 0, SEEK_CUR)                   = 0
read(0, "grep pos /proc/self/fdinfo/0\nIFS"..., 85) = 85
lseek(0, -56, SEEK_CUR)                 = 29
pos:    29
[...]

$ strace -e read,lseek dash < f
read(0, "grep pos /proc/self/fdinfo/0\nIFS"..., 8192) = 85
pos:    85
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12422, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
read(0, "", 1)                          = 0
[...]

Lorsque stdin est un terminal, chaque read() renvoie les lignes telles qu'elles sont envoyées par le terminal, vous voyez donc généralement un comportement similaire dans bash et dash .

Dans votre cas, vous pourriez faire :

sudo dash << 'end-of-script'
su test <<"end"
whoami
end
end-of-script

ou mieux :

sudo sh -c '
  su test -c whoami
'

ou encore mieux :

sudo -u test whoami

Linux
  1. Quel est votre shell préféré pour le travail d'administrateur système ?

  2. Le but de .bashrc et comment ça marche ?

  3. Pourquoi la substitution de processus Bash ne fonctionne-t-elle pas avec certaines commandes ?

  4. Pourquoi le fichier de traduction Bash ne contient-il pas tous les textes d'erreur ?

  5. Pourquoi "zip" dans une boucle For fonctionne-t-il lorsque le fichier existe, mais pas lorsqu'il n'existe pas ?

Pourquoi ce "pendant la lecture" fonctionne-t-il dans un terminal, mais pas dans un script shell ?

Comment lire l'intégralité du script Shell avant de l'exécuter ?

Pourquoi Tomcat fonctionne-t-il avec le port 8080 mais pas 80 ?

Pourquoi Bash est-il partout (dans la plupart sinon toutes les distributions Linux) ?

Pourquoi 'dd' ne fonctionne-t-il pas pour créer une clé USB amorçable ?

Pourquoi SUID est-il désactivé pour les scripts shell mais pas pour les binaires ?