Quelle est la différence entre ./ et sh pour exécuter un script?

71

J'ai écrit un script simple. Quand je cours sh <myscriptname.sh>, j'ai le bon résultat, mais quand je cours ./<myscriptname.sh>, j'ai une erreur.

Quelle est la différence entre quand je fais shet ./?

mr_eclair
la source
15
Au lieu de simplement dire "je reçois une erreur", cela aiderait si vous colliez ce que l'erreur disait.
SpashHit

Réponses:

67

Lorsque vous exécutez un script en transmettant le nom de fichier au programme interpréteur de script, vous exécutez le programme interpréteur avec le script en tant qu'argument passé. Par exemple, cela ressemblerait au processus 'sh' avec l'argument 'filename.sh'. L' shinterprète ouvre le fichier.

D'autre part, si vous exécutez le script lui-même, le système appelle le programme interprète spécifié et alimente le contenu des scripts. Dans ce cas, le processus ressemble à 'filename.sh' sans arguments.

Vous devriez vous assurer que vous avez une ligne bang:

#!/bin/bash
# bash script here

Une ligne éclatée est la toute première ligne du script et commence par les deux mêmes caractères #!. Il s'agit de ce que le système lit lorsqu'il tente d'exécuter le script, puis le système le transmet au programme immédiatement après. Notez que cette ligne n’a rien à voir avec bash et fonctionne aussi bien pour python que pour perl, même si ce sont des langages très différents. Vous utiliseriez #!/usr/bin/pythonpar exemple, puis suiviez avec du code python.

Une fois que vous avez votre script, assurez-vous d’avoir défini les autorisations d’exécution:

chmod a+x filename.sh

Ensuite, vous pouvez exécuter le script en tant que processus propre:

./filename.sh

Ou placez le fichier dans un emplacement connu avec un nom de programme intéressant, comme /usr/sbinpar exemple:

sudo cp filename.sh /usr/sbin/program-name
program-name

Et c’est vraiment l’ avantage pratique d’utiliser la ligne bang avec les autorisations adéquates - tout est une question de déploiement . Il est très difficile d'amener les utilisateurs à exécuter un script s'ils doivent se rappeler avec quel programme exécuter le script. N'oubliez pas de donner un chemin complet au script chaque fois qu'il veut l'exécuter. Par /usr/local/binexemple, le mettre en place et le rendre exécutable peut épargner énormément de chagrin à ceux qui essaient d’utiliser votre script. Ces programmes deviennent alors disponibles pour tous les utilisateurs de votre ordinateur.

C'est aussi bon pour l'identification. Si vous entrez dans le topprogramme, un script exécuté sans la ligne bang n'aura que le nom de l'interprète c'est bash-à- dire , perlou python. Mais si un script est exécuté avec les autorisations appropriées, le nom du script s'affiche.

Remarque: Si vous souhaitez distribuer un script accessible à tous, créez une page de manuel et un package deb pour l'installer. Nous devons réduire le nombre de scripts aléatoires en ligne et augmenter le nombre de debs pouvant être désinstallés.

Martin Owens -doctormo-
la source
1
Vous pouvez également utiliser un dossier bin personnel: créez un dossier bin dans votre dossier personnel, déconnectez-vous et reconnectez-vous. Vous devriez alors pouvoir exécuter tous les scripts de ce dossier sans sh ni ./.
papukaija
Bien sûr, mais l’ajout de votre dossier personnel à votre PATH peut être considéré comme un casse-tête. Mieux vaut installer les choses. Bien qu'il ait été question d'ajouter ~ / .local / bin au chemin par défaut pour permettre aux utilisateurs locaux d'installer des packages.
Martin Owens -doctormo-
Notez que l'interpréteur par défaut est bash, pas sh.
Nathan Osman
1
Ne mettez pas d'extensions sur les scripts, surtout quand vous les insérez PATH.
geirha
1
/usr/local/binest probablement mieux alors /usr/sbin- cela indique que le programme est local pour cette machine plutôt que de faire partie de la distribution.
Glenn Jackman
41

La version courte:

  • shest l'interpréteur de ligne de commande (tiret).
    Courir sh my_scriptpermet à dash d'interpréter le script.

  • ./essaie de trouver quel interprète utiliser, en regardant la première ligne. Par exemple #!/bin/bash, ou même #!/bin/ruby(par opposition à la course ruby my_script).

Stefano Palazzo
la source
7
Ce n'est pas vraiment ./ce qui trouve quelque chose, c'est la méthode d'exécution du système qui examine les deux premiers octets du fichier.
Martin Owens -doctormo-
9
Absolument. Voici une très longue explication de tout cela. Je suis pragmatique :)
Stefano Palazzo
Lorsque vous utilisez shet que le fichier contient un sha-bang, cela signifie-t-il que le sha-bang sera ignoré ou ouvrira-t-il le shell avec les shliens également et peut-être un autre shell ou que fera-t-il :)?
Ini
5

La différence que vous faites est,

  • avec sh, vous exécutez un programme qui interprétera les lignes de votre script exactement comme vous les auriez dactylographiées sur l’invite interactive du terminal,

  • avec ./vous faites un raccourci en supposant que le script est juste ici dans le répertoire courant que vous êtes assis dans et il sera exécutable (parce que , par exemple , vous avez émis chmod +x myscript.sh), gain de temps précieux pour les temps futurs :-)

meduz
la source
3
+1 pour être le seul à déclarer de manière concise que le fichier doit être exécutable.
Mikel
2
Notez que shle fichier ne doit pas nécessairement être exécutable.
Ini
3

Vous pouvez recevoir une erreur pour trois raisons principales:

  • le fichier n'est pas exécutable
    terme chmod +x <myscriptname.sh>pour résoudre ce problème
  • la partition n'autorise pas l'exécution de scripts (est monté " noexec"),
    copiez le script dans/usr/local/bin
  • la #!ligne a une erreur,
    assurez-vous que la première ligne est #!/bin/shou#!/bin/bash

Si votre première ligne semble correcte mais ne fonctionne toujours pas, assurez-vous que le fichier ne comporte pas de fin de ligne DOS.

L'erreur ressemblerait à quelque chose comme ça:

$ ./myscript.sh
bash: ./myscript.sh: /bin/bash^M: bad interpreter: No such file or directory

Vous pouvez le fixer en cours d' exécution dos2unix <myscriptname.sh>, ou si vous ne l' avez pas,
perl -p -i -e 's/\r\n$/\n/' <myscriptname.sh>.

Mikel
la source
0

Et la réponse est que sh est le nom d'une coquille très populaire. Mais obsolète et remplacé par d'autres. De nos jours, sh est lié à d’autres coques installées sur la machine. par exemple, j'ai bash misé là. L'exécution d'un shell à partir de sh déclenche généralement un mode 'compatibilité' avec le comportement 'shell' d'origine.

Donc, la solution est assez simple. Regardez ce qui se cache derrière la commande sh (ls -al / bin / sh), et mettez #! / Bin / any_you_find_there en première ligne (ou s'il y a quelque chose comme ça dans votre script, modifiez-le).

Et alternativement, il peut y avoir un bug dans le script lui-même. Comme la dépendance rencontrée par sh, mais pas l'interprète réellement utilisé.

przemo_li
la source
0
mkdir ~/bin ; cp myscript.sh ~/bin/

echo "export PATH="$PATH:/home/$USER/bin" >> ~/.profile ; source ~/.profile ; 

Non /usr/sbin, c'est pour les outils administratifs non essentiels, /usr/local/binc'est un meilleur choix si vous ne voulez pas en avoir un ~/bin/, mais il sudoest préférable d' éviter autant que possible.

Joey1978
la source
Sur Ubuntu, le ~/.profilecode par défaut contient déjà du code pour l'ajout ~/bin, s'il existe, à PATH. Sur une autre note, ne mettez pas d'extensions sur des scripts.
geirha
1
Je faisais référence à <myscriptname.sh>, mais quelle est la raison pour ne pas ajouter d'extensions à des scripts? Je le fais habituellement parce que les fichiers de texte brut visibles comme ceux-ci m'empêchent d'essayer de modifier les fichiers binaires que je conserve également dans ~ / bin /. ( ls ~/bin/|wc -l = 428) J'ai mis beaucoup de choses là-dedans;)
Joey1978
Imaginez que vous écrivez un script pour accomplir une tâche spécifique. Ensuite, vous réalisez que l'écriture de ce script particulier en python le rendra beaucoup plus efficace. Vous devez donc le réécrire en python. Maintenant vous avez deux choix. 1) Laissez l'extension .sh maintenant très trompeuse, ou 2) renommez le script et recherchez et remplacez toutes les utilisations du script pour utiliser le nouveau nom. Si vous regardez les scripts dans /binet /usr/binvous verrez qu'ils n'utilisent pas d'extensions.
geirha