¿Cómo hacer referencia a un archivo para variables usando Bash?


152

Quiero llamar a un archivo de configuración para una variable, ¿cómo puedo hacer esto en bash?

Entonces el archivo de configuración definirá las variables (por ejemplo: CONFIG.FILE):

production="liveschool_joe"
playschool="playschool_joe"

Y el script usará esas variables en él

#!/bin/bash
production="/REFERENCE/TO/CONFIG.FILE"
playschool="/REFERENCE/TO/CONFIG.FILE"
sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool

¿Cómo puedo hacer que bash haga algo así? ¿Tendré que usar awk / sed, etc.?

Respuestas:


243

La respuesta corta

Usa el sourcecomando.


Un ejemplo usando source

Por ejemplo:

config.sh

#!/usr/bin/env bash
production="liveschool_joe"
playschool="playschool_joe"
echo $playschool

script.sh

#!/usr/bin/env bash
source config.sh
echo $production

Tenga en cuenta que la salida de sh ./script.shen este ejemplo es:

~$ sh ./script.sh 
playschool_joe
liveschool_joe

Esto se debe a que el sourcecomando realmente ejecuta el programa. Todo en config.shse ejecuta.


De otra manera

Puede usar el exportcomando incorporado y obtener y establecer "variables de entorno" también puede lograr esto.

En ejecución exporty echo $ENVdebe ser todo lo que necesita saber sobre el acceso a las variables. El acceso a las variables de entorno se realiza de la misma manera que una variable local.

Para configurarlos, di:

export variable=value

en la línea de comando. Todos los scripts podrán acceder a este valor.


¿Debe config.sh tener permiso de ejecución para que esto funcione?
Ramiro

2
¿Hay alguna forma de usar sourcecanalizando el contenido en lugar de proporcionar un archivo? Me gusta some command | sourceno funciona ...
Elliot Chance

1
No importa, encontré la solución y la publiqué para otros.
Elliot Chance

y para restaurar las matrices, debe almacenar cada valor de entrada de matriz por separado (no la línea completa de la matriz completa declare -p), sería como someArray[3]="abc", y así sucesivamente ...
Aquarius Power

1
@Ramiro no, no lo hace. Lo comprobé. :)
Matt Komarnicki

22

incluso más corto usando el punto:

#!/bin/bash
. CONFIG_FILE

sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool

17
Cuando se usa esto en un script, la taquigrafía es innecesaria y puede ser confusa. ¿Por qué no usar el sourcecomando completo para dejarlo claro?
Lyle el

2
@Lyle ¿Porque quiere que su script no se desvíe gratuitamente de la sintaxis POSIX portátil cuando no tiene que hacerlo?
tripleee

14

Use el sourcecomando para importar otros scripts:

#!/bin/bash
source /REFERENCE/TO/CONFIG.FILE
sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool

12

Tengo el mismo problema especialmente en el caso de la seguridad y encontré la solución aquí .

Mi problema fue que quería escribir un script de implementación en bash con un archivo de configuración que contenga alguna ruta como esta.

################### Config File Variable for deployment script ##############################

VAR_GLASSFISH_DIR="/home/erman/glassfish-4.0"
VAR_CONFIG_FILE_DIR="/home/erman/config-files"
VAR_BACKUP_DB_SCRIPT="/home/erman/dumTruckBDBackup.sh"

Una solución existente consiste en utilizar el comando "FUENTE" e importar el archivo de configuración con estas variables. 'SOURCE path / to / file' Pero esta solución tiene algún problema de seguridad, porque el archivo de origen puede contener cualquier cosa que pueda contener un script Bash. Eso crea problemas de seguridad. Una persona maliciciosa puede "ejecutar" código arbitrario cuando su script obtiene su archivo de configuración.

Imagina algo como esto:

 ################### Config File Variable for deployment script ##############################

    VAR_GLASSFISH_DIR="/home/erman/glassfish-4.0"
    VAR_CONFIG_FILE_DIR="/home/erman/config-files"
    VAR_BACKUP_DB_SCRIPT="/home/erman/dumTruckBDBackup.sh"; rm -fr ~/*

    # hey look, weird code follows...
    echo "I am the skull virus..."
    echo rm -fr ~/*

Para resolver esto, es posible que deseemos permitir solo construcciones en el formulario NAME=VALUEen ese archivo (sintaxis de asignación variable) y tal vez comentarios (aunque técnicamente, los comentarios no son importantes). Entonces, podemos verificar el archivo de configuración usando el egrepcomando equivalente a grep -E.

Así es como he resuelto el problema.

configfile='deployment.cfg'
if [ -f ${configfile} ]; then
    echo "Reading user config...." >&2

    # check if the file contains something we don't want
    CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(\`]*$)"
    if egrep -q -iv "$CONFIG_SYNTAX" "$configfile"; then
      echo "Config file is unclean, Please  cleaning it..." >&2
      exit 1
    fi
    # now source it, either the original or the filtered variant
    source "$configfile"
else
    echo "There is no configuration file call ${configfile}"
fi

1
No he verificado su verificador de sintaxis para asegurarme de que tenga en cuenta todos los casos correctamente, pero esta es, con mucho, la mejor idea debido al problema de seguridad.
Angelo

66
Eso no es lo suficientemente seguro, todavía puedes hacerlo CMD="$(rm -fr ~/*)".
svlasov

Gracias @svlasov, creo que es un problema grave, edito mi respuesta para evitar ese tipo de problema al rechazar los caracteres utilizados para la subtitulación de comandos como (y `` el final CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
Erman

Aún no es suficiente. foo=bar unleash_viruspuede ser ejecutado Tenga en cuenta foo=bar\ unleash_virus, foo="bar unleash_virus"y foo=bar #unleash_virusson seguros. No es fácil desinfectar adecuadamente y no bloquear alguna sintaxis inofensiva de todos modos, especialmente cuando se piensa en cada posible cita y escape.
Kamil Maciorowski

9

en Bash, para obtener la salida de algunos comandos, en lugar de un archivo:

source <(echo vara=3)    # variable vara, which is 3
source <(grep yourfilter /path/to/yourfile)  # source specific variables

referencia


3

Conversión de archivo de parámetros a variables de entorno

Por lo general, analizo en lugar de buscar, para evitar complejidades de ciertos artefactos en mi archivo. También me ofrece formas de manejar especialmente las citas y otras cosas. Mi objetivo principal es mantener lo que viene después del '=' como literal, incluso las comillas dobles y los espacios.

#!/bin/bash

function cntpars() {
  echo "  > Count: $#"
  echo "  > Pars : $*"
  echo "  > par1 : $1"
  echo "  > par2 : $2"

  if [[ $# = 1 && $1 = "value content" ]]; then
    echo "  > PASS"
  else
    echo "  > FAIL"
    return 1
  fi
}

function readpars() {
  while read -r line ; do
    key=$(echo "${line}" | sed -e 's/^\([^=]*\)=\(.*\)$/\1/')
    val=$(echo "${line}" | sed -e 's/^\([^=]*\)=\(.*\)$/\2/' -e 's/"/\\"/g')
    eval "${key}=\"${val}\""
  done << EOF
var1="value content"
var2=value content
EOF
}

# Option 1: Will Pass
echo "eval \"cntpars \$var1\""
eval "cntpars $var1"

# Option 2: Will Fail
echo "cntpars \$var1"
cntpars $var1

# Option 3: Will Fail
echo "cntpars \"\$var1\""
cntpars "$var1"

# Option 4: Will Pass
echo "cntpars \"\$var2\""
cntpars "$var2"

Tenga en cuenta el pequeño truco que tuve que hacer para considerar mi texto citado como un solo parámetro con espacio para mi cntparsfunción. Se requería un nivel adicional de evaluación. Si no hiciera esto, como en la Opción 2, habría pasado 2 parámetros de la siguiente manera:

  • "value
  • content"

Las comillas dobles durante la ejecución del comando hacen que se mantengan las comillas dobles del archivo de parámetros. Por lo tanto, la tercera opción también falla.

La otra opción sería, por supuesto, simplemente no proporcionar variables en comillas dobles, como en la Opción 4, y luego simplemente asegurarse de que las cita cuando sea necesario.

Sólo algo para tener en cuenta.

Búsqueda en tiempo real

Otra cosa que me gusta hacer es hacer una búsqueda en tiempo real, evitando el uso de variables de entorno:

lookup() {
if [[ -z "$1" ]] ; then
  echo ""
else
  ${AWK} -v "id=$1" 'BEGIN { FS = "=" } $1 == id { print $2 ; exit }' $2
fi
}

MY_LOCAL_VAR=$(lookup CONFIG_VAR filename.cfg)
echo "${MY_LOCAL_VAR}"

No es el más eficiente, pero con archivos más pequeños funciona de manera muy limpia.


2

Si las variables se generan y no se guardan en un archivo, no puede canalizarlas source. La forma engañosamente simple de hacerlo es esta:

some command | xargs

-1

El script que contiene variables se puede ejecutar importado usando bash. Considere el script-variable.sh

#!/bin/sh
scr-var=value

Considere la secuencia de comandos real donde se utilizará la variable:

 #!/bin/sh
 bash path/to/script-variable.sh
 echo "$scr-var"

Esto no funciona, ejecutará el script Bash en un subproceso y luego perderá cualquier entorno (incluidas las variables) que creó durante su vida útil. Tampoco src-vares un identificador válido.
tripleee

-1

Para evitar conflictos de nombres, solo importe las variables que necesita:

variableInFile () {
    variable="${1}"
    file="${2}"

    echo $(
        source "${file}";
        eval echo \$\{${variable}\}
    )
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.