Saltar al contenido

¿Qué es “declare” en Bash?

Nuestro equipo de especialistas luego de días de trabajo y recopilar de datos, dieron con la respuesta, nuestro deseo es que te resulte útil para tu trabajo.

Solución:

La salida de help declare es bastante conciso. Se puede encontrar una explicación más clara en man bash o info bash – este último es la fuente de lo que sigue.

Primero, algunas definiciones. Acerca de variables y atributos:

A parámetro es una entidad que almacena valores. … A variable es un parámetro denotado por un name. Una variable tiene un valor y cero o mas atributos. Los atributos se asignan mediante el declare comando incorporado …

Y sobre el declare incorporado:

declare

declare [-aAfFgilnrtux] [-p] [name[=value] …]

Declara variables y dales atributos. Si no se dan nombres, muestre los valores de las variables en su lugar.

-n

Dar cada uno nombre los nameref atributo, convirtiéndolo en una referencia de nombre a otra variable. Esa otra variable está definida por el valor de nombre. Todas las referencias, asignaciones y modificaciones de atributos a nombre, excepto para aquellos que usan o cambian el -n atributo en sí, se realizan en la variable referenciada por nombrevalor de. …

Tenga en cuenta que referencia de nombre las variables solo están disponibles en Bash 4.3 o posterior1.

Además, para una introducción útil a declare y atributos variables en Bash. Le diría esta respuesta a “¿Qué declare name y declare -g ¿hacer? “(que se centra principalmente en el alcance de las variables).


Básicamente2, declare name=[value] es equivalente a la tarea name=[value] probablemente esté familiarizado. En ambos casos, name se le asigna el valor nulo si value Está perdido.

Tenga en cuenta que lo ligeramente diferente declare name, en cambio, no colocar La variable name3:

$ declare name

## With the -p option, declare is used to display
## attributes and values of variables
$ declare -p name
declare -- name            ## "name" exists

## Parameter expansion can be used to reveal if a variable is set:
## "isunset" is substituted to "name" only if unset 
$ echo "$name-isunset"
isunset

Por tanto, la variable name puede ser:

  • declarado y desarmado, después declare name;
  • declarado y colocar con nulo como valor, después name= o declare name=;
  • declarado, colocar y con un no nulo valor después name=value o declare name=value.

Más generalmente, declare [options] name=value

  1. crea la variable name – que es un parámetro con un nombre, que a su vez es solo una parte de la memoria que puede usar para almacenar información4;
  2. asigna el valor value lo;
  3. opcionalmente establece nameatributos, que definen tanto el tipo de valor que puede almacenar (no en términos de un escribe, estrictamente hablando, ya que el lenguaje de Bash no está mecanografiado) y las formas en que se puede manipular.

Los atributos probablemente sean más fáciles de explicar con un ejemplo: usando declare -i name establecerá el atributo “entero” de name, dejando que se trate como un número entero; citando el manual, “la evaluación aritmética se realizará cuando se asigne un valor a la variable”:

## Let's compare an ordinary variable with an integer
$ declare var
$ declare -i int
$ var="1+1"
$ int="1+1"
$ echo "$var"
1+1                 ## The literal "1+1"
$ echo "$int"
2                   ## The result of the evaluation of 1+1

A la luz de lo anterior, lo que está sucediendo en el código de ilkkachu es que:

  1. Una variable llamada ref se declara, con el atributo “nameref” establecido, y el contenido de $1 (el primer argumento posicional) se le asigna:

    declare -n ref="$1"
    

    El objetivo de una variable de referencia de nombre como ref es mantener el nombre de otra variable, que generalmente no se conocería de antemano, posiblemente porque queremos que se defina dinámicamente (por ejemplo, porque queremos reutilizar un fragmento de código y aplicarlo a varias variables), y proporcionar una forma conveniente de referirse a él (y manipularlo). (Sin embargo, no es el único: la indirección es una alternativa; consulte Expansión de parámetros de Shell).

  2. Cuando el valor de la variable tmp1 está asignado a ref:

    ref=$tmp1
    

    una variable adicional, cuyo nombre es el valor de ref, se declara implícitamente. El valor de tmp1 es también indirectamente asignado a la variable implícitamente declarada por medio de esta asignación explícita a ref.

En el contexto de su pregunta vinculada, llamando read_and_verify como

read_and_verify domain "Prompt text here..."

declarará la variable domain y asignarle el valor de tmp1 (es decir, la entrada del usuario). Está diseñado exactamente para reutilizar el código que interactúa con el usuario y aprovechar una variable nameref para declarar domain y algunas otras variables.

Para echar un vistazo más de cerca a la parte implícita podemos reproducir el proceso paso a paso:

## Assign a value to the first positional argument
$ set -- "domain"

## Declare the same "tmp1" variable as in your code
$ tmp1="value for domain"

## Declare a "ref" variable with the nameref attribute set and
## assign the value "domain" to it
$ declare -n ref="$1"

## Note that there is no "domain" variable yet
$ declare -p domain
bash: declare: domain: not found

## Assign a value to "ref" and, indirectly, to the "domain" variable
## that is implicitly declared  
$ ref=$tmp1

## Verify that a variable named "domain" now exists, and that
## its value is that of "tmp1"
$ declare -p domain
declare -- domain="value for domain"

## Verify that "ref" is actually a reference to "domain"
$ domain="new value"
$ echo "$domain"
new value
$ declare -p ref
declare -n ref="domain"
$ echo "$ref"
new value

1 Referencia: archivo CHANGES, sección “3. Nuevas funciones en Bash”, punto “w”.
Esto puede ser relevante: por ejemplo, CentOS Linux 7.6 (actualmente la última versión) se envía con Bash 4.2.

2 Como es habitual con las incorporaciones de shell, una exhaustiva y La explicación concisa es difícil de alcanzar, ya que realizan diversas acciones, posiblemente heterogéneas. Me centraré en declarar, asignar y establecer atributos únicamente, y consideraré enumerar, definir el alcance y eliminar atributos como fuera del alcance de esta respuesta.

3 Este comportamiento de declare -p se ha introducido en Bash 4.4. Referencia: archivo CHANGES, sección “3. Nuevas funciones en Bash”, punto “f”.
Como señaló G-Man en los comentarios, en Bash 4.3 declare name; declare -p name produce un error. Pero aún puedes comprobar eso name existe con declare -p | grep 'declare -- name'.

4 FullBashGuide, Parámetros en mywiki.wooledge.org

En la mayoría de los casos es suficiente con una declaración implícita en bash

asdf="some text"

Pero, a veces, desea que el valor de una variable sea solo un número entero (por lo que, en caso de que cambie más tarde, incluso automáticamente, solo se puede cambiar a un número entero, por defecto es cero en algunos casos), y puede usar:

declare -i num

o

declare -i num=15

A veces quieres matrices y luego necesitas declare

declare -a asdf   # indexed type

o

declare -A asdf   # associative type

Puede encontrar buenos tutoriales sobre matrices en bash cuando navega por Internet con la cadena de búsqueda ‘bash array tutorial’ (sin comillas), por ejemplo

linuxconfig.org/how-to-use-arrays-in-bash-script


Creo que estos son los casos más comunes cuando declaras variables.


Tenga en cuenta también que

  • en una función, declare hace que la variable sea local (en la función)
  • sin ningún nombre, enumera todas las variables (en el shell activo)

    declare
    

Finalmente, obtiene un breve resumen de las características del comando integrado de shell declare en bash con el comando

help declare

Intentaré explicar esto, pero perdóname si no sigo el ejemplo que me diste. Prefiero tratar de guiarte a lo largo de mi propio enfoque diferente.

Dices que ya entiendes conceptos como “variables” y “expandirlas”, etc., de modo que solo echaré un vistazo a algunos conocimientos previos que, de otro modo, requerirían un enfoque más profundo.

Así que empezaré diciendo que, a lo sumo básico nivel, el declare El comando es solo una forma de decirle a Bash que necesita un valor de variable (es decir, un valor que podría cambiar durante la ejecución del script), y que se referirá a ese valor con un nombre específico, precisamente el nombre que indique junto al declare mandarse a sí mismo.

Es decir:

declare foo="bar"

le dice a Bash que quieres que la variable se llame foo tener el valor bar.

Pero … espere un minuto … podemos hacerlo sin usar declare en absoluto, no podemos. Como en:

foo="bar"

Muy cierto.

Bueno, da la casualidad de que la simple asignación anterior es en realidad una implícito manera de .. de hecho .. declarar una variable.

(También sucede que lo anterior es uno de algunas formas de cambio el valor de la variable nombrada foo; de hecho, es precisamente la forma más directa, concisa, evidente y sencilla .. pero no es la única .. .. Volveré sobre esto más tarde ..).

Pero entonces, si es tan posible declarar un “nombre que etiquetará los valores de las variables” (solo “variable” de aquí en adelante, en aras de la brevedad) sin usar declare en absoluto, ¿por qué querrías usar este pomposo comando de “declarar”?

La respuesta radica en el hecho de que la forma implícita anterior de declarar una variable (foo="bar"), esto … implícitamente … hace que Bash considere que la variable es del tipo que se usa más comúnmente en el escenario de uso típico de un shell.

Este tipo es el tipo de cadena, es decir, una secuencia de caracteres sin un significado particular. Por lo tanto, una cadena es lo que obtiene cuando usa la declaración implícita.

Pero usted, como programador, a veces necesita considerar una variable como, por ejemplo, un número … en el que necesita hacer operaciones aritméticas … y usar una declaración implícita como foo=5+6no lo haré hacer que Bash asigne el valor 11 a foo como se podría esperar. Preferirá asignar a foo la secuencia de los tres personajes 5+6.

Entonces … necesitas una forma de decirle a Bash que quieres foo para ser considerado un número, no una cadena … y eso es lo que un explícito declare resulta útil para.

Sólo decir:

declare -i foo=5+6  # <<- note the '-i' option: it means 'integer'

y Bash felizmente hará los cálculos por usted y le asignará el numérico valor 11 a variable foo.

Es decir: diciendo declare -i foo le das a la variable foo los atributo de ser un número entero.

Declarar números (precisamente enteros, porque Bash todavía no entiende decimales, puntos flotantes y todo eso) puede ser la primera razón para usar declare, pero no es la única razón. Como ya ha entendido, hay algunos otros atributos que puede asignar a las variables. Por ejemplo, puede hacer que Bash siempre ponga el valor de una variable en mayúsculas sin importar qué: si dice declare -u foo, luego de ahí en adelante cuando digas foo=bar Bash realmente asigna la cadena BAR a la variable foo.

Para otorgar cualquiera de estos atributos a una variable, debe debe utilizar el declare comando, no hay otra opción.


Ahora, otro de los atributos que puedes dar a través de declare es el infame "name-ref" uno, el -n atributo. (Y ahora voy a retomar el concepto que dejé en suspenso antes.).

El atributo name-ref, básicamente, permite a los programadores de Bash otra forma de cambiar el valor de una variable. Más precisamente da una indirecto manera de hacer eso.

Aquí está cómo funciona:

usted declare una variable que tiene el -n atributo, y es muy recomendado (aunque no estrictamente obligatorio, pero simplifica las cosas) que también le des un valor esta muy variable en el mismo declare mando. Como esto:

declare -n baz="foo"

Esto le dice a Bash que, a partir de ese momento, cada vez que usará o cambiará el valor de la variable denominada baz, utilizará o cambiará el valor de la variable denominada foo.

Lo que significa que, a partir de ese momento, puedes decir algo como baz=10+3 para hacer foo obtenga el valor de 13. Suponiendo, por supuesto, que foo fue previamente declarado como entero (declare -i) como hicimos hace un minuto, de lo contrario obtendrá la secuencia de los cuatro caracteres 10+3.

Además: si cambias foovalor directamente, como en foo=15, verá 15 también diciendo echo “$baz”. Esto se debe a que la variable baz declarado como name-ref de foo siempre refleja foovalor de.

Lo anterior declare -n comando se dice un "nombre-referencia" porque hace variable bazreferir al nombre de otra variable. De hecho hemos declarado baz tiene valor "foo" que, debido a la -n opción, es manejada por Bash como el nombre de otra variable.

Ahora, por qué en la Tierra, ¿alguna vez querrías hacer eso?

Bueno ... vale la pena decir que esta es una característica para necesidades bastante avanzadas.

De hecho, es tan avanzado que cuando un programador se enfrenta a un problema que realmente requeriría una referencia de nombre, también es probable que dicho problema deba abordarse utilizando un lenguaje de programación adecuado en lugar de Bash.

Una de esas necesidades avanzadas es, por ejemplo, cuando usted, como programador, no puede saber durante el desarrollo cuales variable que tendrá que usar en un punto específico de un script, pero voluntad ser plenamente conocido dinámicamente en tiempo de ejecución. Y dado que no hay forma de que ningún programador intervenga en tiempo de ejecución, la única opción es hacer una provisión antemano para tal situación en el guión, y una "referencia de nombre" puede ser la única forma viable. Como caso de uso ampliamente conocido de esta necesidad avanzada, piense en complementos, por ejemplo. El programador de un programa "compatible con complementos" debe realizar una provisión genérica para complementos futuros (y posiblemente de terceros) de antemano. Por lo tanto, el programador necesitará utilizar funciones como una referencia de nombre en Bash.

Otra necesidad avanzada es cuando tienes que lidiar con una gran cantidad de datos. en RAM y también necesita pasar esos datos a las funciones de su secuencia de comandos que además tienes que modificar esos datos en el camino. En tal caso, ciertamente podría Copiar esos datos de una función a otra (como lo hace Bash cuando lo haces dest_var="$src_var" o cuando invocas funciones como en myfunc "$src_var"), pero al tratarse de una gran cantidad de datos, supondría un gran desperdicio de RAM y para una operación muy ineficiente. Entonces, la solución, si surgen tales situaciones, es usar no una copia de los datos, sino una referencia a esos datos. En Bash, un nombre-ref. Este caso de uso es realmente la norma en cualquier lenguaje de programación moderno, pero es bastante excepcional cuando se trata de Bash, porque Bash está diseñado principalmente para scripts cortos y simples que se ocupan principalmente de archivos y comandos externos y, por lo tanto, los scripts Bash rara vez tienen que pasar grandes cantidad de datos entre funciones. Y cuando las funciones de un script necesitan compartir algunos datos (acceder a ellos y modificarlos), esto generalmente se logra usando una variable global, que es bastante común en los scripts Bash tanto como lo es. muy en desuso en los lenguajes de programación adecuados.

Entonces, puede haber un caso de uso notable para referencias de nombre en Bash, y (tal vez irónicamente) está asociado cuando usa otros tipos de variables:

  1. variables que se declaran como "matrices indexadas" (declare -a)
  2. variables que se declaran como "matrices asociativas" (declare -A).

Estos son un tipo de variables que pueden más fácilmente (así como de manera más eficiente) transmitió funciones mediante el uso de referencias de nombre en lugar de mediante la copia normal, incluso cuando no contienen grandes cantidades de datos.

Si todos estos ejemplos suenan extraños y aún incomprensibles, es solo porque las referencias de nombres son de hecho un tema avanzado y una rara necesidad para el escenario de uso típico de Bash.

Podría contarles sobre ocasiones en las que, por mi parte, he encontrado uso para referencias de nombres en Bash, pero hasta ahora han sido principalmente para necesidades bastante "esotéricas" y complicadas, y me temo que si las describiera, solo las complicarle las cosas en este punto de su aprendizaje. Solo por mencionar el menos complejo (y posiblemente no esotérico): devolver valores de funciones. Bash realmente no es compatible con esta funcionalidad, por lo que obtuve lo mismo usando name-refs. Esto, dicho sea de paso, es exactamente lo que hace su código de ejemplo.


Además de esto, un pequeño consejo personal, que en realidad sería más adecuado para un comentario, pero no he podido condensarlo lo suficiente para encajar en los límites de comentarios de StackExchange.

Creo que lo mas lo que debe hacer en este momento es simplemente experimentar con referencias de nombre utilizando los ejemplos simples que mostré y tal vez con el código de ejemplo que proporcionó, sin tener en cuenta por el momento la parte "por qué en la tierra" y centrándose solo en "cómo funciona " parte. Experimentando un poco, la parte del "cómo" puede penetrar mejor en su mente, de modo que la parte del "por qué" le resultará clara a su debido tiempo cuando (o si) tendrá un problema práctico real para el cual un nombre- ref sería realmente útil.

Puntuaciones y comentarios

Más adelante puedes encontrar las explicaciones de otros creadores, tú también puedes dejar el tuyo si te apetece.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *