¿Puede el nombre de la variable de shell incluir un guión o guión (-)?

38

No puedo usar -variables en shell. ¿Hay alguna manera de poder usarlo, porque tengo un script que depende de tales variables nombradas:

$export a-b=c
-bash: export: `a-b=c': not a valid identifier

$export a_b=c

Primero arroja el error dado y el segundo funciona bien.

xyz
fuente
posible duplicado entre sitios de: stackoverflow.com/questions/2821043/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Los shells generalmente no permiten nombres de variables de este tipo. Tendría que omitir el shell, tal vez incluso con un programa C personalizado que carga las variables en el entorno de su comando. ¿No puede solucionar este error (incluso el posible riesgo de seguridad)?
vonbrand

Respuestas:

47

Nunca he conocido un shell de estilo Bourne que permita -un nombre variable. Solo _se admiten letras ASCII (de cualquier caso) y dígitos, y el primer carácter no debe ser un dígito.

Si tiene un programa que requiere una variable de entorno que no coincide con las restricciones de shell, ejecútelo con el envprograma.

env 'strange-name=some value' myprogram

Tenga en cuenta que algunos shells (por ejemplo , guiones modernos , mksh, zsh) eliminan del entorno las variables cuyo nombre no les gusta. ( Shellshock ha provocado que las personas sean más cautelosas con los nombres de variables de entorno, por lo que es probable que las restricciones se vuelvan más estrictas con el tiempo, no más permisivas). Entonces, si necesita pasar una variable cuyo nombre contiene caracteres especiales a un programa, páselo directamente, sin un caparazón intermedio ( env 'strange-name=some value' sh -c'…; myprogram'puede o no funcionar).

Gilles 'SO- deja de ser malvado'
fuente
Ya no funciona
Jesse Glick
44
@JesseGlick Sí, lo hace. (Tu comentario sería útil si ha definido “no trabajar”: con lo que los datos de lo que es el efecto en lugar del efecto deseado y si usted ha dicho, que la aplicación de?? envSe utiliza en el sistema operativo.)
SO ser parada de Gilles malvado '
Lo siento. Ubuntu Yakkety con todas las actualizaciones, envdesde coreutils, shdesde dash: env 'with-dashes=value' bash -c 'env | fgrep dashes'funciona pero env 'with-dashes=value' sh -c 'env | fgrep dashes'no imprime nada. Es decir, envsí está bien, pero Dash parece bloquear específicamente estas variables. Por lo tanto, si el programa en cuestión se inicia a través de un contenedor de shell con un #!/bin/shencabezado típico , no hay forma aparente de pasar esas variables. ejemplo de solución
Jesse Glick el
@JesseGlick Eso es un guión que elimina la variable. Debe usarlo envmás cerca del sitio de llamada del programa que necesita este nombre de variable, sin un shell intermedio. Dash no está solo en la eliminación de variables cuyo nombre no le gusta.
Gilles 'SO- deja de ser malvado'
1
@JesseGlick Sin embargo, es cierto que algunas cosas que solían funcionar ya no funcionan: desde shellshock , las personas se han vuelto más conservadoras con respecto a los nombres de variables, y el guion cambió de hecho desde que escribí esta respuesta (no como consecuencia de Shellshock, pero para evitar un error en la misma línea). He agregado una nota a mi respuesta.
Gilles 'SO- deja de ser malvado'
15

Eso no es posible en Bash.

Desde la sección Definiciones en la página del manual de bash:

nombre Una palabra que consta solo de caracteres alfanuméricos y guiones bajos, y que comienza con un carácter alfabético o un guión bajo. También se conoce como un identificador.

Desde la sección Parámetros en la página del manual de bash:

Un parámetro es una entidad que almacena valores. Puede ser un nombre, un número o uno de los caracteres especiales enumerados a continuación en Parámetros especiales. Una variable es un parámetro denotado por un nombre.

Lekensteyn
fuente
2
+1 por demostrar la utilidad de las páginas man una vez más
ktf
2
Publicación anterior, lo sé, pero quiero señalar que para los recién llegados las páginas de manual pueden ser bastante crípticas. Todavía tengo momentos en los que necesito buscar mejores explicaciones / ejemplos. Cualquiera estaría mintiendo si dijera que nunca les sucedió.
TCZ8
1
@ TCZ8 Las únicas personas que me han dicho que pensaban que las páginas de manual eran 'crípticas' son el mismo tipo de personas que no leen mensajes de error y simplemente leen todo, pasando por alto lo que necesitan leer.
Miles Rout
13

Puede acceder a una variable con guión utilizando una referencia indirecta.

$ env 'my-hyphenated-variable=hello' /bin/bash
$ name='my-hyphenated-variable'
$ echo ${!name}
hello
Jon Nalley
fuente
1
Nunca había oído hablar de esta funcionalidad hasta que leí este comentario. Me proporcionó una solución mucho más fácil que la respuesta aceptada.
DrStrangepork
77
Este comportamiento se ha deshabilitado en las versiones más recientes de bash. Consulte stackoverflow.com/questions/36989263/… para un análisis exhaustivo de la situación.
Nicolas Dudebout
6

Si su script depende de que los nombres de las variables tengan guiones, es un error de programación. Si es conveniente para usted debido a las herramientas que usa regularmente para que los nombres de las variables contengan un guión, es posible que deba aprender más y diferentes herramientas.

¿Has intentado usar tr para convertir los guiones en guiones bajos?

hyphenated_name="a-b"
unhyphenated_name=$(echo $hyphenated_name | tr '-' '_')
declare -x $unhyphenated_name="some value"

Bash permite que aparezca '-' en los nombres de las funciones. Hago esto todo el tiempo. Por ejemplo:

function foo-bar() {
   echo "$@"
}
Brian J. Fox
fuente
2

El carácter guión ( -) es un carácter de corte y no está permitido como parte de los nombres de variables. Hay formas de hackear esto con variables citadas, pero su análisis es realmente problemático. También hay otros caracteres con significados especiales en el contexto de nombres de variables en bash, especialmente llaves, paréntesis, caracteres de operador y comillas. (p. ej. {}()=+-&'"y más)

Sugeriría que prácticamente necesita encontrar otro paradigma sobre el cual construir su script. Es posible que tenga una idea de otros idiomas sobre "nombres de variables variables". Esto generalmente no es una buena idea en los scripts de shell.

Si edita esto o hace una nueva pregunta con detalles de su contexto y lo que está tratando de lograr, podríamos sugerirle una buena forma de escribirlo.

Caleb
fuente
2

El manual de Bash define un "nombre" como:

Una 'palabra' que consiste únicamente en letras, números y guiones bajos, y que comienza con una letra o guión bajo. 'Los nombres se usan como variables de shell y nombres de funciones. También se conoce como 'identificador'.

Entonces no puedes usar un guión en un nombre.

Michael Hoffman
fuente
0

La mayoría de los shells solo admiten az, AZ, 0-9 y _ para nombres de variables. Lea el segundo elemento en esta página .


fuente
0

Puedes jugar con env y sed.

Como ejemplo, necesitaba leer esta variable 'ELASTICSEARCH_CLUSTER-NODES'.
El comando env genera esto:

~ $ env
ELASTICSEARCH_CLUSTER-NODES=elasticsearch:9200
JAVA_ALPINE_VERSION=8.212.04-r0
HOSTNAME=17eb9e7fec4c
...

Entonces para extraer la variable:

ESHOST=`env | sed -n 's/ELASTICSEARCH_CLUSTER-NODES=\(.*\)/\1/p'`
Guillaume Paramelle
fuente
-1

Creo que solo se permiten letras, números y guiones bajos para las variables bash. Este es el caso en muchos lenguajes de programación (javascript es una excepción).

Recomiendo que su script no dependa de esos tipos de nombres de variables.

De hecho, debe intentar programar de tal manera que pueda reemplazar los nombres de las variables con otros nombres y eso no hace la diferencia. En general, los nombres de las variables deben describir lo que contiene la variable. Esto facilita mucho la depuración; si no es por ti, entonces por el próximo desarrollador que está tratando de descifrar el código.


fuente
-1

Puede usar el envcomando para establecer y desarmar variables de entorno con guiones "-".

Para configurar debe utilizar env para ejecutar su comando: env command. Pasas variables de esta manera:

env a-b=c command

Véalo trabajando con:

env a-b=c env

o para hacerlo más claro:

env a-b=c env|grep 'a-b'
neves
fuente