Bonjour
Je souhaiterais qu'on m'explique la différence entre ces trois instructions shell :
Code:variable=valeur commande
Code:env variable=valeur commande
MerciCode:variable=valeur ; commande
Version imprimable
Bonjour
Je souhaiterais qu'on m'explique la différence entre ces trois instructions shell :
Code:variable=valeur commande
Code:env variable=valeur commande
MerciCode:variable=valeur ; commande
Bonjour
Le point-virgule sépare les instructions. Ca équivaut à
En général je m'en sers pour les "if" et "while". Je trouve plus sympa d'écrireCode:
1
2variable=valeur commande
queCode:
1
2
3 while truc; do ... done
Code:
1
2
3
4 while truc do ... done
Pour les deux autres j'en ai aucune idée sauf que chez-moi, aucune des deux n'a fonctionné. Je n'ai pas eu d'erreur, la commande s'est exécutée mais ma variable est restée vide.
va modifier la valeur de variable avec valeur ou affecter la valeur valeur à variable le temps de l’exécution de commande.Code:env variable=valeur commande
C'est parce que le shell développe les variables avant d'exécuter la commande, donc au moment où il considère l'assignation xxx=123 la variable xxx n'existe plus dans l'expression à droite.
Ceci serait différent :
La première et la deuxième commandes en OP modifient toutes les deux l'environnement de commande avant de l'exécuter. La différence est que la première utilise une syntaxe shell pour le faire, alors que la deuxième utilise la commande env, qui permet un contrôle plus fin, et qui ne nécessite pas d'interpréteur shell pour fonctionner (donc elle peut être directement utilisée dans un lanceur par exemple).Code:env xxx=123 sh -c 'echo $xxx'
Je commence à comprendre. C'est un début. Mais, pourquoi avec cette instruction ci-dessous c'est différent ?
Je peux dire ici aussi que le shell va développer xxx dans la partie sh -c 'echo $xxx' avant d'exécuter l'assignation xxx=123 ! Je ne vois pas la différenceCode:env xxx=123 sh -c 'echo $xxx'
Autre question : s'il te plaît. peux-tu détailler cette réponse :
La commande env permet un contrôle plus fin, qui ne nécessite pas d'interpréteur shell pour fonctionner (donc elle peut être directement utilisée dans un lanceur par exemple)
Oui c'est un peu subtil
Dans l'écriture xxx=123 echo $xxx, au moment où tu valides ta commande par <return> le shell remplace "$xxx" par sa valeur. Et c'est cette valeur qui est envoyée à "echo". Mais cette valeur n'existe pas encore puisque le processus "echo" n'existe pas encore. Donc ça équivaut à
Code:
1
2 xxx=123 echo
Dans l'écriture xxx=123 sh -c 'echo $xxx' ce sont les quotes simples qui font toute la différence. Parce que les quotes simples désactivent tous les métacaractères y compris le métacaractère "$" (teste echo '$HOME' puis echo "$HOME" par exemple).
Donc là, le shell ne voit pas de variable à développer. Il voit juste une bête string à envoyer à "echo".
Et c'est quand le processus "echo" est exécuté que là, la variable "$xxx" prend tout son sens. Mais là, la variable existe.
Non tu ne peux pas le dire (enfin tu peux mais c'est faux :)), car l'emploi de guillemets simples empêche le développement de variables par le shell.
Là tu pourrais le dire :
Voir man env pour le contrôle plus fin, env permet par exemple d'enlever une variable de l'environnement avant exécution.Code:env xxx=123 sh -c "echo $xxx"
Pour les lanceurs je parle des fichiers .desktop qu'on utilise dans les environnements de bureau.
Dans ces fichiers, tu ne peux pas mettre directement xxx=123 commande comme commande à exécuter, car cette syntaxe nécessite un interpréteur shell (c'est du code shell).
Mais tu peux mettre env xxx=123 commande, car ici l'assignation xxx=123 est un argument de la commande env, ça n'est pas du code shell.
Excellent. Tout ça c'est excellent
Je pense que j'ai compris, mais confirmez le :-)
Le but final du sujet que j'ai posté est pour comprendre le fonctionnement de ces deux commandes :
Code:sudo PATH=$PATH script # ne fonctionne pas : le chemin du script est inconnu
Code:sudo env PATH=$PATH script # fonctionne
1) Dans les deux instructions, le shell va développer la valeur $PATH avant d'exécuter le script. Donc ici, c'est la valeur PATH de l'utilisateur lambda (et non du root) qui est envoyée (correct ?)
2) Cependant, dans la première instruction, l'assignation PATH=$PATH est locale et n'est pas exporté vers le script, car ce dernier lance un processus fils qui n'est plus celui du shell actif courant (correct ?)
3 ) La deuxième fonctionne, parce que comme tu as dit, la commande env est spéciale et permet d'exporter les variables aux processus fils (dans notre cas, c'est notre script) (correct ?)
4) La deuxième instruction est équivalente à 100% à :
et non à :Code:sudo sh -c "export PATH=$PATH ; script"
MerciCode:sudo sh -c 'export PATH=$PATH ; script'
Bizarre, car les deux doivent fonctionner.
Exemple: script "toto.sh"
Code:
1
2
3 #!/usr/bin/env bash echo "xxx=[$xxx]"
De là
Ce n'est pas "env" qui envoie la variable au script, c'est le fait que le script soit sur la même ligne d'instruction.Code:
1
2
3
4
5 $ xxx=123 ./toto.sh xxx=[123] $ env xxx=123 ./toto.sh xxx=[123] $
Là oui. Le PATH de l'user est copié dans un "PATH fils" et c'est ce "PATH fils" qui est utilisé dans le sudo.
Non. Les deux devraient fonctionner.
Modification toto
Code:
1
2
3 #!/usr/bin/env bash echo "PATH=[$PATH]"
De là
Le PATH est bien transmis à "toto.sh".Code:
1
2
3
4
5
6
7 $ PATH="/usr/bin" ./toto.sh PATH=[/usr/bin] $ env PATH="/usr/bin" ./toto.sh PATH=[/usr/bin] $ ./toto.sh PATH=[/home/moi/bin:/usr/local/pgsql/bin:/usr/local/pgadmin3/bin:/usr/local/bin:/usr/bin:/bin:/usr/games:/home/moi/bin] $
Après il peut y avoir d'autres trucs. Par exemple le PATH est un élément assez important et même utilisé de façon standard, doit être exporté car les fils en ont besoin. Alors utilisé de cette façon? Et avec un "sudo" en plus qui peut rajouter des effets de bord éventuels???
Tu as raison et je me suis trempé. Le chemin PATH de l'utilisateur lambda est transmis dans les deux instructions :
etCode:sudo PATH=$PATH script.sh
Mais je ne comprends pas pourquoi la première instruction ne fonctionne pas sachant que le chemin du script.sh est inclus dans l'environnement PATH de lambda. Ça retourne l'erreur comme ceciCode:sudo env PATH=$PATH script.sh
Testez avec une commande qui existe dans le chemin PATH de lambda et non du root et vous verrez !Code:sudo: script.sh : commande introuvable
Quelqu'un peut nous expliquer ?
Exact (viens de le faire). M'a suffit de copier "toto.sh" dans mon bin. De là
Ok on est d'accord, ça ne fonctionne pas. C'est parce que le PATH n'est pas encore modifié quand root tente d'appeler "toto.sh" et ne sait donc pas où le trouver.Code:
1
2
3
4
5 $ sudo PATH=$PATH toto.sh [sudo] Mot de passe de moi*: sudo: toto.sh*: commande introuvable $ sudo env PATH=$PATH toto.sh PATH=[/home/moi/bin:/usr/local/pgsql/bin:/usr/local/pgadmin3/bin:/usr/local/bin:/usr/bin:/bin:/usr/games:/home/moi/bin]
Oui. Suffit de coupler cet exemple avec celui de balkany.
Je teste ceci (grand merci à balkany qui m'a montré la syntaxe). Et là...
De là ça recolle avec l'idée de départ qu'a montré balkany avec son excellent exemple. Le shell développe PATH avant d'appeler toto.sh. Sauf que le PATH de root ne connait pas le chemin de toto.sh (qui est dans mon bin et non dans celui de root) donc root ne peut pas exécuter toto.shCode:
1
2 $ sudo PATH=$PATH sh -c 'toto.sh' PATH=[/home/moi/bin:/usr/local/pgsql/bin:/usr/local/pgadmin3/bin:/usr/local/bin:/usr/bin:/bin:/usr/games:/home/moi/bin]
Tandis qu'avec sh -c, là le PATH est maintenant connu du process "sh" qui, de fait, sait aller chercher "toto.sh". En fait, tout se résume à "la variable n'est modifiée que dans le process demandé et pas avant".
Ah !
Mais pourquoi @Sve@r ?
C'est parce que le Shell va tenter d'exécuter "PATH=$PATH toto.sh" en une seule fois toute la commande comme seul bloc ?, c'est bien ça ?
Parce que moi, je vois "PATH=$PATH toto.sh" comme succession de deux commandes " "PATH=$PATH puis toto.sh " donc le script toto.sh " aura le nouveau chemin PATH modifié. (Je me trempe alors)
Oui. Le PATH ne sera modifié que dans le processus "toto.sh" mais si le procesuss ne peut pas être lancé parce que le shell ne sait pas où trouver toto.sh...:?
C'est la base. Ensuite il y a "env" qui doit jouer un rôle là dedans. Probablement (hypothèse) parce que "env" a pour but de modifier l'environnement et que, de fait, là la variable est alors connue permettant alors de lancer "toto.sh"...
Non. Deux commandes distinctes c'est soit sur deux lignes (avec un <return> par ligne), soit avec un point-virgule entre les deux.
Ça avance :
Mais en suivant ton raisonnement pourquoi alors :
#fonctionneCode:sudo env PATH=$PATH toto.sh
Je peux dire aussi (comme tu l'as dit : c'est un extrait de ton message) :
le PATH n'est pas encore modifié (avec env PATH=$PATH ) quand root tente d'appeler "toto.sh" et ne sait donc pas où le trouver.
Ah, d'accord. Merci tout le monde. J'ai compris beaucoup de choses grâce à vous. Mais pour arriver à 100 % de compréhension :-) , je chercherai dans le man de la commande env pour comprendre pourquoi
Fonctionne.Code:sudo env PATH=$PATH toto.sh
C'est la seule étape qui reste
Balkani a essayé peut-être de l'expliquer, mais je ne l'ai pas compris
Citation Balkani : Voir man env pour le contrôle plus fin, env permet par exemple d'enlever une variable de l'environnement avant exécution.
Oui c'est vrai que "env" est un outil à décortiquer. Le man dit "env - run a program in a modified environment". Donc c'est en quelque sorte une espèce de "bac à sable". Et couplé avec un var=truc ça donne (ou ça "doit donner") un environnement dans lequel la variable existe, contrairement aux autres essais faits sans. 8-)