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-)
La solution existe avec "sudo env PATH=$PATH toto.sh" mais il est important de comprendre pourquoi une solution fonctionne et l'autre non. Je dois corriger un grand script qui bogue à cause de ce problème (des commandes invalides non reconnues) et on m'a chargé d'expliquer les raisons de ce bug dans un rapport
Si je comprends bien ...
- ton problème n'est pas de passer la variable d'environnement dans ton script appelé par sudo
- dans ton script principal, en fait $PATH n'est PAS ta variable d'environnement
Tu modifies $PATH dans ton script principal ? (avant ton code donné)
Ton problème est que tu ne sais pas modifier ta variable d'environnement ? donc ton script principal ne trouve pas le second script dans cette variable d'environnement
Ce nouveau PATH doit être très temporaire ???
PATH="$NEWPATH" sudo toto.sh PATH="$PATH:/nouveau dir/bin" sudo toto.sh.
ou,
la bonne question initiale était simplement comment changer une variable d'environnement dans un script (et ces sous-scripts) ...
En déroulant le fil de discussion :mrgreen: on est passé de variable=valeur commande (assez générique) à variable/[commande, prog ou script param].
Je ne suis pas expert en Linux :mrgreen: mais :
- lorsque tu remplaces 1 truc simple et universel par 1 truc tordu normal que lorsque cela marche ou pas tu ne peux pas vraiment expliquer pourquoi (ici on peut voir cela comme 2 threads concurrents qu'on veut dire "thread 1 puis thread 2")
- lorsque dans 1 commande simple (lancer 1 script) tu es obligé de créer 1 """sous shell""", c'est qu'il y a quelque chose de mauvais :aie: :aie: (avec env ou carrément avec sh -c 'XXXX')
Donne leur l'URL de ce topic...:aie:
En fait, c'est "env" qui fait que ça marche mais en même temps, qui fout la zone dans la compréhension. Et avec le fait que la variable modifiée soit justement le PATH (variable assez primordiale dans la gestion des processus) ça aide pas non plus.
C'est simplement parce que vous n'avez pas compris comment fonctione la syntaxe:
cette syntaxe crée une variable "locale" à la commande de DROITE , donc sudo ne voit pas l'affectation de PATH, par contre pour la commande env , c'est différent, car pour elle c'est un paramètre qu'elle doit tenir compte et dont c'est le boulot.Code:variable=valeur commande
Code:
1
2
3 $ env --help Utilisation*: env [OPTION]... [-] [NOM=VALEUR]... [COMMANDE [ARG]...] Initialiser chaque NOM à VALEUR dans l'environnement et exécuter COMMANDE.
Ce que tu dis est vrai pour la syntaxe variable=valeur sudo commande, mais pas pour la syntaxe sudo variable=valeur commande. Dans ce dernier cas, variable=valeur est un argument de sudo comme il l'est pour env, et donc sudo pourrait le traiter comme le fait env (cf. https://www.developpez.net/forums/d2.../ ), mais elle ne le fait pas.
Non, soit tu as fait une typo et inversé tes 2 commandes sudo dans ton explication (ce qui serait plus logique pour moi):
ceci ne fonctionne pas car sudo par mesure de sécurité ne tient pas compte de l'environnement appelantCode:PATH=$PATH sudo commande
ne permet pas à sudo de trouver la commande car on lui dit juste de fournir une variable à la commande mais pas de l'intégrer dans son env.Code:sudo PATH=$PATH commande
pour preuve:
Code:
1
2
3 #!/bin/bash echo $PATH
comme on peut le voir ici, PATH n'est pas modifié dans mon shell appelant (c'est pareil pour sudo)Code:
1
2
3
4
5
6
7
8 $ echo $PATH /opt/disedorgue/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin $ ./pre.sh /opt/disedorgue/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin $ PATH=/bin ./pre.sh /bin $ echo $PATH /opt/disedorgue/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
Ah, ça je savais pas :applo:
Ca oui je l'avais déjà décrit ici.
D'où sudo PATH=$PATH sh -c 'commande' afin que ce soit "sh" qui lance la commande ; sh processus déjà lancé à ce moment là donc connaissant le PATH modifié. 8-)
ça peut être contourner avec --perserve-env[=LIST] ?
Pense pas.
En reprenant mon "toto.sh" copié dans mon bin, j'ai tenté...
... mais rien n'a réussi.Code:
1
2 sudo --preserve-env=PATH toto.sh sudo --preserve-env=PATH PATH=$PATH toto.sh
En revanche, en modifiant "toto.sh" pour lui faire afficher "$var", puis en écrivant export var=123, alors sudo --preserve-env=var ./toto.sh fonctionne.
Donc le "--preserve-env" c'est pour transmettre au fils, pas pour permettre au PATH d'évoluer afin de pouvoir créer ce fils.
@disedorgue: je maintiens :)
Cette syntaxe a besoin d'être interprétée par un shell: variable=valeur sudo commande, et ce que fait le shell est d'ajouter variable=valeur à l'environnement de la commande sudo commande avant de la lancer.
Le fait que sudo ignore l'environnement appelant est un autre problème.
Cette syntaxe n'a pas besoin d'être interprétée par un shell: sudo variable=valeur commande, car variable=valeur est un argument de la commande sudo (et commande en est un autre argument), tout comme il est un argument de la commande env dans les posts précédents.
Le fait que sudo traite cet argument "comme le fait le shell" (manifestement) et non pas comme le fait env, est en quelques sortes accidentel : essentiellement c'est un argument, et sudo pourrait en faire autre chose.
C'est cette distinction que je voulais faire, mais pour le reste je constate comme vous le comportement démontré.
Pour le premier cas, on est d'accord, c'est un problème inhérent à sudo.
Pour le deuxième cas, tu auras le même souci que sudo via Bash ou autre shell car la définition de la variable est juste pour la commande de droite : sudo n'est rien d'autre qu'une surcouche à sh qui permet au sh de se lancer dans un autre env.
Ce que je veux dire par là, c'est que pour sudo, il n'a qu'un seul paramètre, toute la ligne (ou jusqu'au ; )