Son variables como $ 0 y $ 1 las variables de shell / medio ambiente?

17

Hay variables en la cáscara como $0, $1, $2, $?, etc.

Traté de imprimir las variables de shell y el medio ambiente mediante el siguiente comando:

set

Pero estas variables no estaban en la lista.

Básicamente, estas variables no se consideran variables de shell / entorno, ¿verdad? (aunque para generarlos, debe precederlos con un $, como lo hace con las variables de shell / entorno)

usuario7681202
fuente
3
Los parámetros posicionales no son variables. No puede export 3convertirse $3en una variable de entorno. No puedes unset 3; y no puede asignar $3un nuevo valor usando 3=val.
Kaz

Respuestas:

25

Las variables son una de las tres variedades distintas de parámetros en shell.

  1. Una variable de es un parámetro cuyo nombre es un identificador de shell válida; comienza con _o una letra, seguido de cero o más letras, números o _.
  2. Los posicionales parámetros son los parámetros numerados $1, $2, ...
  3. Los especiales todos los parámetros tienen nombres de un solo carácter, y aparte de $0, todos ellos son diferentes signos de puntuación.

set sólo se muestra las variables de la cáscara.

Un subconjunto de las variables de shell son las variables de entorno, cuyos valores se heredan del entorno cuando se inicia el shell o se crean estableciendo export atributo en un nombre válido.

chepner
fuente
1
Tenga en cuenta que setmuestra todos los parámetros en zsh(no $ 1, $ 2 ... pero $ *, $ @) y las funciones en bash y bosh. Algunos shells como ksh93 y versiones anteriores de env envían resultados de salida que no se asignaron a variables de shell. ( env 1=foo ksh -c setimprimiría 1=foo)
Stéphane Chazelas
11

Variables de entorno vs Parámetros posicionales

Antes de comenzar a analizar el $INTEGERtipo de variables, debemos comprender cuáles son realmente y cómo difieren de las variables de entorno. Variables como $INTEGERlas denominadas parámetros posicionales. Esto se describe en el estándar POSIX (Interfaz del sistema operativo portátil), sección 2.1 (énfasis mío):

  1. El shell ejecuta una función (vea Comando de definición de función), incorporado (vea Utilidades incorporadas especiales), archivo ejecutable o script, dando los nombres de los argumentos como parámetros posicionales numerados del 1 al n, y el nombre del comando (o en el caso de una función dentro de una secuencia de comandos, el nombre del script) como el parámetro posicional el número 0 (ver comando Buscar y Ejecución).

Por el contrario, variables como $HOMEy $PATHson variables de entorno. Su definición se describe en la sección 8 de la norma. :

Las variables de entorno definidas en este capítulo afectan al funcionamiento de múltiples utilidades, funciones y aplicaciones. Hay otras variables de entorno que son de interés sólo para los servicios públicos específicos. Las variables de entorno que se aplican a una única utilidad sólo se definen como parte de la descripción de utilidad.

Observe su descripción. Los parámetros posicionales están destinados a aparecer en frente de un comando, es decir command positional_arg_1 positional_arg_2.... Ellos están destinados a ser proporcionada por el usuario para contar lo que específicamente comando a hacer. Cuando lo haga echo 'Hello' 'World', imprimirá las cadenas Helloy World, porque estos son parámetros posicionales para echolas cosas sobre las que desea echooperar. Y echoestá construido de tal manera que entiende los parámetros posicionales como cadenas para imprimir (a menos que sean uno de los indicadores opcionales como -n). Si lo hace con diferentes comandos que podría no entender qué HelloyWorldes porque tal vez espera un número. Observe que los parámetros posicionales no se "heredan": un proceso secundario no conoce los parámetros posicionales del padre a menos que se pase explícitamente al proceso secundario. A menudo se ve parámetros posicionales que se pasa con los scripts de envoltura - los que tal vez comprueban por ejemplo ya existente de un comando o añadir parámetros de posición adicionales para el comando real que se llama.

Por el contrario, las variables de entorno están destinadas a afectar múltiples programas. Son entorno de variables, porque están fuera del conjunto del programa en sí (más sobre esto más adelante). Ciertas variables de entorno como HOMEo PATHtienen formato específico, significado específico, y significarán lo mismo para cada programa. HOMEvariable significa igual a cualquiera de utilidad externa como /usr/bin/findo su shell (y por consiguiente a una secuencia de comandos) - es el directorio inicial del nombre de usuario bajo el que se ejecuta el proceso. Tenga en cuenta que las variables ambientales se pueden utilizar para dar cuenta de la conducta comando específico, por ejemplo,UIDLa variable de entorno se puede utilizar para verificar si el script se ejecuta con privilegios de root o no y se ramifica a acciones específicas en consecuencia. Las variables de entorno son heredables - procesos hijos reciben copia del entorno de los padres. Véase también Si los procesos heredan el entorno del padre, ¿por qué necesitamos exportar?

En resumen, la principal distinción es que las variables de entorno se establecen fuera del comando y no están destinadas a ser variadas (generalmente), mientras que los parámetros posicionales son cosas que el comando debe procesar y cambiar.


No solo conceptos de shell

Lo que me he dado cuenta de los comentarios es que se está mezclando terminal y concha, y que se lo recomendaría leer acerca de los terminales reales que en otro tiempo eran dispositivos físicos. Hoy en día, el "terminal" al que normalmente nos referimos, esa ventana con fondo negro y texto verde es en realidad software, un proceso. Terminal es un programa que se ejecuta una concha, mientras que la cáscara es también un programa, sino el que lee lo que se escribe en la ejecución (es decir, si se trata de shell interactivo; conchas no interactivas son secuencias de comandos y sh -c 'echo foo'tipos de invocaciones). Más sobre cáscaras de aquí .

Esta es una distinción importante, pero también es importante reconocer que el terminal es un programa y, por lo tanto, se adhiere a las mismas reglas de entorno y parámetros posicionales. Tu gnome-terminalcuando se inicia se verá en su SHELLvariable de entorno, y generar el shell por defecto apropiado para usted, a menos que se especifique algún otro comando con -e. Digamos que cambié mi shell predeterminado a ksh - gnome-terminal se generará en kshlugar de bash. Ese también es un ejemplo de cómo los programas usan el entorno. Si se lo digo de forma explícita gnome-terminalcon el -ecorrer cáscara específica - lo hará, pero no va a ser permanente. Por el contrario, el medio ambiente está mayormente inalterado (más sobre eso más adelante).

Como puede ver, las variables de entorno y de posición son propiedades de un proceso / comando, no solo shell. Cuando se trata de scripts de shell, también siguen el modelo establecido por el lenguaje de programación C. Tomemos por ejemplo el C mainfunción que normalmente se ve como

int main(int argc, char **argv)

, Donde argces el número de argumentos de línea de comandos y argves efectivamente matriz de parámetros de línea de comandos, y luego está environla función (en Linux que de man -e 7 environ) a las cosas de acceso como la ruta del directorio principal del usuario, lista de directorios en PATHdonde podemos buscar los ejecutables, etc. scripts de shell también se modelan de forma similar. En terminología de shell, tenemos parámetros posicionales $1, $2y así sucesivamente, mientras que $#es el número de parámetros posicionales. ¿Qué hay de $0? Ese es el nombre del ejecutable en sí, que también está modelado a partir del lenguaje de programación C: argv[0]sería el nombre de su C "ejecutable". Y esto es bastante cierto para la mayoría de lenguajes de programación y script .

conchas interactiva vs no interactivas

Una de las cosas que ya he insinuado es la distinción entre shells interactivos y no interactivos . El mensaje donde escribe los comandos: es interactivo, interactúa con el usuario. Por el contrario, cuando usted tiene un script de shell o ejecutar bash -c''eso es no interactivo.

Y aquí es donde la distinción se vuelve importante. La cáscara que ya ejecuta un proceso, que se generó con los parámetros de posición (por bashshell de entrada es una "... cuyo primer carácter del argumento es un cero -., O uno iniciado con la opción --login" ( referencia ) )

Por el contrario, las secuencias de comandos y proyectiles lanzados con -copción puede aprovechar $1y $2argumentos. Por ejemplo,

$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
  File: '/etc/passwd'
  Size: 2913        Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 6035604     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
 Birth: -

Tenga en cuenta que también lo he usado shallí, porque una pequeña peculiaridad de la -copción es tomar el primer parámetro posicional y asignarlo, a $0diferencia de ser un nombre del programa.

Otra cosa que es importante tener en cuenta es que los parámetros posicionales son lo que yo llamo "framable". Observe cómo, primero lanzamos bashcon sus propios parámetros posicionales, pero esos parámetros posicionales se convirtieron en parámetros para echoy stat. Y cada programa lo entiende a su manera. Si le damos a statuna cadena Hello Worldy no hay archivo Hello World, produciría un error; bashlo trata simplemente como una cadena simple, pero statespera que cadena a un nombre de archivo existente. Por el contrario, todos los programas estarían de acuerdo en que la variable de entorno HOMEes un directorio (a menos que el programador lo codifique de manera no razonable).


¿Podemos jugar con las variables de entorno y los parámetros posicionales?

Técnicamente, podemos perder el tiempo con ambos, pero no debemos perder el tiempo con las variables de entorno, mientras que a menudo tenemos que proporcionar parámetros posicionales. Podemos ejecutar comandos de shell con anteponiendo una variable, por ejemplo:

$ hello=world bash -c 'echo $hello'
world

También podemos colocar variables en el entorno simplemente usando export variable=valuedesde shell o script. O podemos ejecutar un comando con un entorno completamente vacío con env -c command arg1 arg2. Sin embargo, generalmente no se recomienda jugar con el entorno, especialmente usando variables en mayúsculas o sobrescribiendo variables de entorno ya existentes. Tenga en cuenta que se recomienda aunque no es una norma.

Para los parámetros posicionales, la manera de ponerlos es obvio, sólo les anteponer al comando, sino que también hay formas de establecer ellos de otra forma , así como el cambio de la lista de los parámetros a través shiftde comandos.

En conclusión, el propósito de estos dos es diferente, y que existe por una razón. Espero personas obtuvieron una idea de esta respuesta, y fue muy divertido leyendo casi como lo fue para mí escribir esta respuesta.


Nota sobre el mandato set

El setcomando, de acuerdo con el manual, se comporta así (del manual bash, énfasis agregado):

Sin opciones, el nombre y el valor de cada variable de shell se muestran en un formato que se puede reutilizar como entrada para establecer o restablecer las variables establecidas actualmente.

En otras palabras setmira a variables específicas a Shell, algunos de los cuales resultan ser en el entorno, por ejemplo HOME. Por órdenes de contraste como envy printenvvistazo a la variable de entorno real con la que se ejecuta un comando. Ver también esto .

Sergiy Kolodyazhnyy
fuente
"En shell interactivo, no puede hacer referencia $ 1, $ 2, y así sucesivamente." ¿Hay una referencia directa para esto? Me he encontrado con casos extraños donde éstas están ubicadas en un entorno shell interactivo y no estoy seguro de si esto sería considerado 'no estándar' o no.
user5359531
@ user5359531 Honestamente, no estoy muy seguro de dónde lo obtuve. Probablemente debido a la espalda cuando me envió la respuesta en 2017 probablemente referenciado que no se puede hacer algo así 1="foo", pero más tarde descubrí que por POSIX definición de una "palabra" (que es un nombre de un objeto como variable o función) no puede comenzar con un dígito (véase una pregunta que he publicado sobre el tema ). Los parámetros posicionales aparentemente son una excepción a esta regla.
Sergiy Kolodyazhnyy
@ user5359531 He eliminado la parte de la respuesta, ya que no es particularmente precisa. Puede hacer referencia $1, $2y así sucesivamente en el intérprete de comandos interactivo, y, de hecho, que se hace con el setcomando, a menudo para moverse por /bin/shla limitación de no tener matrices. Gracias por traer esto a mi atención. También voy a editar la respuesta en los próximos días, ya que se necesita un poco de esmalte extra y una actualización.
Sergiy Kolodyazhnyy
Gracias por la aclaración. El problema que estoy teniendo es que con conda, cuando se ejecuta source conda/bin/activate, comprueba si $1, $2, etc., se establecen, con el fin de determinar si se ejecuta como un script con argumentos o no. Esto termina rompiendo en sistemas que tienen los fijados en el entorno interactivo por alguna razón. Tengo la esperanza de averiguar si este comportamiento no estándar es una falla en el sistema de fijación de estas variables en el entorno interactivo, o en el programa para el uso de ellos para determinar si se ejecuta como un script.
user5359531
@ user5359531 me gustaría sugerir que presente un informe de error a condalos desarrolladores oa quienquiera que sea el autor original de dicha escritura, como la comprobación de ${N}los parámetros es definitivamente el camino equivocado. Hay preguntas sobre el mismo tema aquí y aquí , y de manera más o menos portátil es comprobar si ${0}es el mismo que el nombre del script, mientras que bashen realidad tiene la variable de entorno para tal fin
Sergiy Kolodyazhnyy
4

Las $1, $2, $3, ..., ${10}, ${11}variables se denominan parámetros posicionales y se tratan en la sección del manual bash3.4.1

3.4.1 Parámetros de posición

Un parámetro de posición es un parámetro indicado por uno o más dígitos, aparte de la de un solo dígito 0. Los parámetros posicionales se asignan de los argumentos de la shell cuando se invoca, y puede ser reasignado utilizando el conjunto de orden interna de comandos. parámetro de posición N puede ser referenciado como $ {N}, o como $ N cuando N consta de un solo dígito. Los parámetros posicionales no pueden ser asignados a con instrucciones de asignación. El conjunto de cambio y órdenes internas se utilizan para armar y desarmar ellos (ver interna del shell de comandos). Los parámetros posicionales se reemplazan temporalmente cuando se ejecuta una función de shell (véase Funciones de Shell).

Cuando se expande un parámetro de posición que consiste en más de un solo dígito, que debe estar encerrada entre llaves.

En cuanto a $?y $0, estos parámetros especiales se tratan en la siguiente sección3.4.2

3.4.2 Parámetros especiales

La cáscara trata a varios parámetros especialmente. Estos parámetros solo pueden ser referenciados; no se permite la asignación a ellos.

...

?

($?) Se expande al estado de salida de la tubería de primer plano ejecutado más recientemente.

0 0

($ 0) Se expande al nombre del shell o script de shell. Esto se establece en la inicialización shell. Si Bash se invoca con un archivo de comandos (ver secuencias de comandos shell), $ 0 se establece en el nombre de ese archivo. Si Bash se inicia con la opción -c (consulte Invocación de Bash), entonces $ 0 se establece en el primer argumento después de la cadena que se ejecutará, si hay uno presente. De lo contrario, se establece en el nombre del archivo utilizado para invocar Bash, como se indica por el argumento cero.

Jesse_b
fuente
4

$1, $2... son los parámetros de posición , no son variables, dejar que las variables de entorno solo.

En Bourne-como terminología cáscara, $somethingse llama parámetro de expansión (también cubre ${something#pattern}y más en algunas cáscaras como ${array[x]}, ${param:offset}, ${x:|y}y muchos operadores de más de expansión).

Hay diferentes tipos de parámetros:

  • variables como $foo,$PATH
  • parámetros posicionales ( $1, $2... los argumentos que recibió su script)
  • otros parámetros especiales como $0, $-, $#, $*, $@, $$, $!, $?...

nombres de las variables en Bourne como conchas deben comenzar con un carácter alfabético (cualquier reconocida por la configuración regional o límite la a-zA-Z en función de la cáscara) y el guión bajo y seguido de cero o más caracteres alfanuméricos o guiones.

Dependiendo de la cáscara, las variables pueden tener diferentes tipos (escalar, matriz, hash) o ciertos atributos dados (de sólo lectura, exportados caso, inferior ...).

Algunas de estas variables son creados por el shell o tienen un significado especial para el shell (como $OPTIND, $IFS, $_...)

Las variables de shell que tienen el atributo de exportación se exportan automáticamente como variables de entorno a los comandos que ejecuta el shell.

variable de entorno es un concepto separado de variables de shell. Exportar una variable de shell no es la única forma de pasar una variable de entorno a la ejecución de un comando.

VAR=foo
export VAR
printenv VAR

pasará una VARvariable de entorno para el printenvcomando (que le estamos diciendo a imprimir su contenido), pero también se puede hacer:

env VAR=foo printenv VAR

o:

perl -e '$ENV{VAR}="foo"; exec "printenv", "VAR"'

por ejemplo.

Las variables de entorno pueden tener cualquier nombre (pueden contener cualquier carácter, sino =e incluso puede estar vacía). No es una buena idea para dar un nombre que no es compatible con el de un nombre de variable Bourne-como la cáscara de una variable de entorno, pero es posible:

$ env '#+%=whatever' printenv '#+%'
whatever

Conchas trazarán las variables de entorno que se reciben para bombardear las variables sólo para aquellas variables de entorno cuyos nombres son válidos variables de shell (y en algunos proyectiles ignoran algunos especiales como $IFS).

Entonces, si bien podría pasar una 1variable de entorno a un comando:

$ env '1=whatever' printenv 1
whatever

Eso no significa que llamar a un shell con esa variable de entorno establecería el valor del $1parámetro:

$ env '1=whatever' sh -c 'echo "$1"' script-name foo bar
foo
Stéphane Chazelas
fuente
3

No, estos son parámetros del script. Por ejemplo, si llamas a tu script como:

mynicescript.sh one two three

a continuación, dentro de la secuencia de comandos, habrá estos parámetros disponibles como

$1 = one
$2 = two
$3 = three

y los $ 0 es el nombre del script mismo.

Así que cuando estás fuera del guión, estas variables no están disponibles (excepto $ 0, lo que muestra / bin / bash - el depósito propiamente dicho).

Jaroslav Kucera
fuente
"Así que cuando esté fuera del guión, estas variables no está disponible" ¿Qué quiere decir por "fuera del guión" , porque puedo ver los valores de estas variables en mi terminal.
user7681202
2
@ user7681202: cuáles puede ver en su terminal? $0apunten a su proceso de terminal (bash probable) actual y $?es simplemente el código de salida del último proceso.
Jesse_b
Traté de correr el gnome-terminalcon argumentos ( gnome-terminal Hello World). Pude ver $0, pero no pude ver $1y $2.
user7681202
@Jesse_b Gracias, he añadido el contenido de $ 0 en la respuesta.
Jaroslav Kucera
1
@ user7681202 El gnome-terminal no es shell, es un emulador de terminal (como xterm, konsole, etc.). Las carreras de concha dentro de la terminal y puede ser bash / sh / zsh / tcsh y muchos más. El script es un archivo ejecutable con el encabezado adecuado (como #! / Bin / bash) y contenido interpretable por el shell especificado en la máscara. Por lo general, utiliza el sufijo .sh
Jaroslav Kucera