2012-05-14 21 views
47

¿Por qué todos los archivos de script empezar conshell-script (#!/bin/sh vs #!/bin/csh)

#!/bin/sh 

o con

#!/bin/csh 

es el requerido? ¿Cuál es el propósito de esto? ¿Y cuál es la diferencia entre los dos?

+1

Para una secuencia de comandos csh, debe usar '#!/Bin/csh -f'; el '-f' le dice al shell que no procese el' .login' y '.cshrc' del usuario, lo que hace que el script se ejecute más rápido y evita dependencias en la configuración del usuario. (O mejor aún, no escriba scripts csh.) No use '-f' para sh o bash scripts; no tiene el mismo significado. –

Respuesta

54

Esto se conoce como un Shebang:

http://en.wikipedia.org/wiki/Shebang_(Unix)

# intérprete [opcional-arg]

Un shebang solo es relevante cuando un script tiene el permiso de ejecución (p. chmod u + x script.sh).

Cuando un shell ejecuta el script, utilizará el intérprete especificado.

Ejemplo:

#!/bin/bash 
# file: foo.sh 
echo 1 

$ chmod u+x foo.sh 
$ ./foo.sh 
    1 
+0

El enlace de arriba necesita ser arreglado. – Levon

+1

¿Necesita agregar '#!/Bin/sh' a' .profile'? –

+0

@Kolob Canyon no es necesario, pero puede ayudar a algunos editores con resaltado de sintaxis (aunque generalmente hay otras formas de lograr lo mismo): https://unix.stackexchange.com/a/88730/193985 –

4

Define qué shell (intérprete de comandos) está utilizando para interpretar/ejecutar su secuencia de comandos. Cada shell es ligeramente diferente en la forma en que interactúa con el usuario y ejecuta scripts (programas).

Cuando escribe un comando en el indicador de Unix, está interactuando con el shell.

Por ejemplo, #!/bin/csh se refiere a la C-shell, /bin/tcsh la t-shell, /bin/bash la cáscara del golpe, etc.

Se puede decir, que shell interactivo que está utilizando el comando

echo $SHELL 

, o alternativamente

env | grep -i shell 

puede cambiar su shell de comandos con el comando chsh.

Cada uno tiene un conjunto de comandos ligeramente diferente y la forma de asignar variables y su propio conjunto de construcciones de programación. Por ejemplo, la sentencia if-else con bash se ve diferente a la que aparece en C-shell.

This page puede ser de interés, ya que "traduce" entre los comandos/sintaxis bash y tcsh.

El uso de la directiva en el script de shell le permite ejecutar programas utilizando un shell diferente. Por ejemplo, uso el shell tcsh de forma interactiva, pero a menudo ejecuto scripts bash usando/bin/bash en el archivo de script.

Aparte:

Este concepto se extiende a otras secuencias de comandos también. Por ejemplo, si se programa en Python que había puesto

#!/usr/bin/python 

en la parte superior de su programa Python

+0

¿Es necesario? ¿Cómo sé qué shell realmente estoy usando? –

+0

Así que si estoy escribiendo los guiones para que los use alguien en su máquina, y no sé qué shell están usando. (Esta persona, desafortunadamente, no tiene ni idea de esto, así que todo lo que puede hacer es ejecutar el script sin cambiar nada). ¿Puedo hacer algo como '#! $ SHELL'? ¿Esto pondría el caparazón correcto en el Shebang? –

+1

@OneTwoThree La mayoría de los sistemas tienen las cubiertas estándar, si escribes un script bash o csh estarás bien. Qué shell están usando interactivamente ** no importa, esa es la belleza de, por ejemplo, la dirección '! #/Bin/bash'. Le dice al sistema qué shell usar para ejecutar su script de shell. – Levon

36

La línea #! le dice al núcleo (en concreto, la implementación del sistema de execve llamada) que este programa está escrito en un lenguaje interpretado; la ruta de acceso absoluta que sigue identifica al intérprete. Los programas compilados para el código de máquina comienzan con una secuencia de bytes diferente, en la mayoría de Unixes modernos, 7f 45 4c 46 (^? ELF) que los identifica como tales.

Se puede retener una ruta absoluta a cualquier programa que desee después de la #!, siempre que ese programa no es en sí un guión #!. El núcleo reescribe una invocación de

./script arg1 arg2 arg3 ... 

donde ./script comienza con, digamos, #! /usr/bin/perl, como si la línea de comandos en realidad había sido

/usr/bin/perl ./script arg1 arg2 arg3 

O, como se ha visto, se puede utilizar #! /bin/sh escribir un script destinado a ser interpretado por sh.

La línea #! se procesa únicamente si directamente invoca el guión (./script en la línea de comandos); el archivo también debe ser ejecutable (chmod +x script). Si lo hace sh ./script, la línea #! no es necesaria (y se ignorará si está presente), y el archivo no tiene que ser ejecutable. El punto de la función es para permitirle invocar directamente programas de idiomas interpretados sin tener que saber en qué idioma están escritos. (Do grep '^#!' /usr/bin/*) descubrirá que hay una gran cantidad de programas de inventario que utilizan esta función.)

Estas son algunas reglas para usar esta característica:

  • el #! deben ser los dos primeros bytes muy en el archivo. En particular, el archivo debe tener en una codificación compatible con ASCII (por ejemplo, UTF-8 funcionará, pero UTF-16 no) y no debe comenzar con con una "marca de orden de bytes", o el kernel no lo hará reconocerlo como un script #!.
  • La ruta después de #! debe ser una ruta absoluta (comienza con /). No puede contener espacios, tabulaciones o caracteres de nueva línea.
  • Es un buen estilo, pero no es necesario, para poner un espacio entre el #! y el /. No pongas más de un espacio allí.
  • No puede poner variables de shell en la línea #!, no se expandirán.
  • Puede poner un argumento de línea de comandos después de la ruta absoluta, separada de ella por un espacio simple. Al igual que la ruta absoluta, este argumento no puede contener espacios, tabulaciones o caracteres de nueva línea. A veces esto es necesario para hacer que las cosas funcionen (#! /usr/bin/awk -f), a veces es útil (#! /usr/bin/perl -Tw). Desafortunadamente, no puede poner dos o más argumentos después de la ruta absoluta.
  • Algunas personas le dirá que use #! /usr/bin/env interpreter en lugar de #! /absolute/path/to/interpreter. Esto es casi siempre un error. Hace que el comportamiento de su programa dependa de la variable $PATH del usuario que invoca el script. Y no todos los sistemas tienen env en primer lugar.
  • Los programas que necesitan los privilegios setuid o setgid no pueden usar #!; deben compilarse para código de máquina. (Si usted no sabe lo que setuid es decir, no se preocupe por esto.)

En cuanto csh, se refiere a sh aproximadamente como Nutrimat Advanced Tea Substitute hace al té. Tiene (o mejor dicho, las implementaciones modernas de sh han alcanzado) una serie de ventajas sobre sh para el uso interactivo, pero su uso (o su descendiente tcsh) para la creación de scripts es almost always a mistake. Si eres nuevo en las secuencias de comandos de shell en general, te recomiendo que lo ignores y te centres en sh. Si está utilizando un pariente csh como shell de inicio de sesión, cambie a bash o zsh, de modo que el idioma del comando interactivo sea el mismo que el del lenguaje de scripts que esté aprendiendo.

+1

excelente consejo –

+0

Las versiones recientes de Linux permiten que el intérprete especificado sea un script. Es una práctica común omitir el espacio después del '#!'; no comenta si es un buen estilo. Ver [esta pregunta] (http://unix.stackexchange.com/q/29608/10454) y [mi respuesta] (http://unix.stackexchange.com/a/29620/10454) para una discusión de los pros y contras del truco '#!/usr/bin/env'. –

+0

@KeithThompson Tengo la impresión de que Linux es la * única * variante común de Unix que permite que el intérprete sea un guión, por lo que todavía no es algo en lo que confiar. Desde que escribí esto, me encontré con una situación en la que '#!/Usr/bin/env' era lo correcto, pero sigue siendo mi opinión que casi siempre es una mala idea. – zwol

Cuestiones relacionadas