¿Cuál es la diferencia entre ./ y sh para ejecutar un script?

71

He escrito un guión simple. Cuando corro sh <myscriptname.sh>, obtuve el resultado correcto, pero cuando corro ./<myscriptname.sh>, recibí un error.

¿Cuál es la diferencia entre cuando lo hago shy ./?

mr_eclair
fuente
15
En lugar de decir simplemente "recibo un error", sería útil si pegaras lo que dice el error.
SpashHit

Respuestas:

67

Cuando ejecuta un script pasando el nombre del archivo al programa de intérprete de script, está ejecutando el programa de intérprete con el script como un argumento que se le pasa. Por ejemplo, esto se vería como el proceso 'sh' con el argumento 'filename.sh'. El shintérprete está abriendo el archivo.

Por otro lado, si ejecuta el script en sí, el sistema llama al programa de intérprete especificado y alimenta el contenido del script. En este caso, el proceso se parece a 'filename.sh' sin argumentos.

Debes asegurarte de tener una línea de explosión:

#!/bin/bash
# bash script here

Una línea de explosión es la primera línea del script y comienza con los mismos dos caracteres #!, estos son los que el sistema lee cuando intenta ejecutar el script y luego el sistema pasa el script al programa inmediatamente después. Tenga en cuenta que esta línea no tiene nada que ver con bash y funciona igual de bien para python y perl, a pesar de que son idiomas muy diferentes. Usaría, #!/usr/bin/pythonpor ejemplo, y luego lo seguiría con el código de Python.

Una vez que tenga su script, asegúrese de haber configurado los permisos de ejecución:

chmod a+x filename.sh

Luego puede ejecutar el script como su propio proceso:

./filename.sh

O coloque el archivo en una ubicación conocida con un buen nombre de programa, como /usr/sbiny ejecute desde cualquier lugar:

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

Y este es realmente el beneficio práctico de usar la línea de explosión con los permisos correctos: se trata de la implementación . Es muy difícil lograr que los usuarios ejecuten un script si tienen que recordar con qué programa ejecutar el script. Recuerde dar una ruta completa al script cada vez que quieran ejecutarlo. Donde ponerlo, /usr/local/binpor ejemplo, y hacerlo ejecutable, puede ahorrar una gran pena para las personas que intentan usar su script. Estos programas estarán disponibles para todos los usuarios en su computadora.

También es bueno para la identificación. Si ingresa al topprograma, una secuencia de comandos ejecutada sin la línea de explosión solo tendrá el nombre del intérprete bash, es decir , perlo python. Pero si se ejecuta un script con los permisos correctos, entonces se muestra el nombre del script.

Nota: Si desea distribuir una secuencia de comandos que sea accesible para todos, cree una página de manual y un paquete deb para instalarlo. Necesitamos reducir la cantidad de scripts aleatorios en línea y aumentar la cantidad de debs que se pueden desinstalar.

Martin Owens -doctormo-
fuente
1
También puede usar una carpeta bin personal: cree una carpeta bin en su carpeta de inicio de sesión, cierre sesión y vuelva a iniciarla, y luego debería poder ejecutar cualquier script en esa carpeta sin sh o ./.
papukaija
Por supuesto, pero agregar su carpeta de inicio a su RUTA puede ser un poco dolor de cabeza. Mejor instale las cosas. Aunque se habló de agregar ~ / .local / bin a la ruta de forma predeterminada para permitir que los usuarios locales instalen paquetes.
Martin Owens -doctormo-
Tenga en cuenta que el intérprete predeterminado es bash, no sh.
Nathan Osman el
1
No coloque extensiones en los scripts, especialmente no cuando lo ingrese PATH.
geirha
1
/usr/local/binprobablemente sea mejor entonces /usr/sbin: indica que el programa es local para esta máquina en lugar de ser parte de la distribución.
Glenn Jackman
41

La versión corta:

  • shes el intérprete de línea de comandos (guión).
    La ejecución sh my_scripthace que dash interprete el script.

  • ./intenta averiguar qué intérprete usar, mirando la primera línea. Por ejemplo #!/bin/bash, o incluso #!/bin/ruby(en lugar de correr ruby my_script).

Stefano Palazzo
fuente
77
No es realmente lo ./que encuentra nada, es el método de ejecución del sistema que analiza los dos primeros bytes del archivo.
Martin Owens -doctormo-
9
Absolutamente. Aquí hay una explicación muy larga de todo. Estoy siendo pragmático :)
Stefano Palazzo
Cuando usa shy el archivo contiene un sha-bang, ¿significa que el sha-bang será ignorado o abrirá el shell donde shtambién se vincula y luego tal vez algún otro shell o qué hace :)?
Ini
5

La diferencia que haces es

  • con sh, está ejecutando un programa que interpretará las líneas en su secuencia de comandos tal como las habría escrito en el mensaje interactivo del terminal,

  • con el ./que está haciendo un acceso directo suponiendo que la secuencia de comandos está justo aquí en el directorio actual en el que está sentado Y será ejecutable (porque, por ejemplo, emitió chmod +x myscript.sh), ahorrándole un tiempo invaluable para tiempos futuros :-)

Meduz
fuente
3
+1 por ser el único que indica de manera concisa que el archivo debe ser ejecutable.
Mikel
2
Tenga en cuenta que con shel archivo no necesariamente debe ser ejecutable.
Ini
3

Hay tres razones principales por las que puede recibir un error:

  • el archivo no es ejecutable
    ejecute chmod +x <myscriptname.sh>para arreglar eso
  • la partición no permite ejecutar scripts (está " noexec" montado ),
    copie el script en/usr/local/bin
  • la #!línea tiene un error,
    asegúrese de que la primera línea es #!/bin/sho#!/bin/bash

Si su primera línea se ve bien, pero aún no funciona, asegúrese de que el archivo no tenga terminaciones de línea DOS.

El error se vería así:

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

Puede solucionarlo ejecutando dos2unix <myscriptname.sh>, o si no tiene eso
perl -p -i -e 's/\r\n$/\n/' <myscriptname.sh>,.

Mikel
fuente
0

Y la respuesta es que sh es el nombre de un shell muy popular. Pero anticuado y reemplazado por otros. Hoy en día sh está vinculado a otras carcasas instaladas en la máquina. Por ejemplo, he golpeado allí. Ejecutar cualquier shell desde sh generalmente desencadena un modo de "compatibilidad" con el comportamiento original de "shell".

Entonces la solución es bastante simple. Mire lo que hay detrás del comando sh (ls -al / bin / sh) y coloque #! / Bin / whatever_you_find_there como primera línea (o si hay algo así en su script, edítelo).

Y, alternativamente, puede haber algún error en el script en sí. Como la dependencia que cumple sh, pero no el intérprete que realmente se usa.

przemo_li
fuente
0
mkdir ~/bin ; cp myscript.sh ~/bin/

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

No /usr/sbin, eso es para herramientas administrativas no esenciales, /usr/local/bines una mejor opción si no desea tener una ~/bin/, pero sudoes aconsejable evitar tanto como sea posible.

Joey1978
fuente
En Ubuntu, el valor predeterminado ~/.profileya tiene código para agregar ~/bin, si existe, a PATH. En otra nota, no ponga extensiones en los scripts.
geirha
1
Estaba haciendo referencia a <myscriptname.sh>, pero ¿cuál es la razón para no poner extensiones en los scripts? Por lo general, lo hago porque tener los archivos de texto sin formato visibles me impide tratar de editar archivos binarios que también mantengo en ~ / bin /. ( ls ~/bin/|wc -l = 428) Puse muchas cosas allí;)
Joey1978
Imagina que escribes un guión para lograr una tarea específica. Entonces te das cuenta de que escribir este script en particular en Python lo hará mucho más eficiente, así que lo reescribes en Python. Ahora tienes dos opciones. 1) Deje la extensión .sh ahora muy engañosa, o 2) cambie el nombre del script y busque y reemplace todos los usos del script para usar el nuevo nombre. Si observa los scripts /biny /usr/binverá que no usan extensiones.
geirha 02 de