Come fare riferimento a un file per le variabili usando Bash?


152

Voglio chiamare un file di impostazioni per una variabile, come posso farlo in bash?

Quindi il file delle impostazioni definirà le variabili (es: CONFIG.FILE):

production="liveschool_joe"
playschool="playschool_joe"

E lo script utilizzerà quelle variabili al suo interno

#!/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

Come posso ottenere bash per fare qualcosa del genere? Dovrò usare awk / sed ecc ...?

Risposte:


243

La breve risposta

Usa il sourcecomando


Un esempio usando source

Per esempio:

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

Si noti che l'output di sh ./script.shquesto esempio è:

~$ sh ./script.sh 
playschool_joe
liveschool_joe

Questo perché il sourcecomando esegue effettivamente il programma. Tutto config.shviene eseguito.


Un altro modo

È possibile utilizzare il exportcomando integrato e anche ottenere e impostare "variabili di ambiente" può farlo.

In esecuzione exporte echo $ENVdovrebbe essere tutto ciò che devi sapere sull'accesso alle variabili. L'accesso alle variabili di ambiente avviene come una variabile locale.

Per impostarli, dire:

export variable=value

alla riga di comando. Tutti gli script saranno in grado di accedere a questo valore.


Config.sh deve avere i permessi di esecuzione affinché questo funzioni?
Ramiro,

2
Esiste un modo per utilizzare il sourcepiping nel contenuto anziché fornire un file? Come some command | sourcenon funziona ...
Elliot Chance,

1
Non importa, ho trovato la soluzione e l'ho pubblicata per altri.
Elliot Chance,

e per ripristinare gli array, è necessario memorizzare separatamente ciascun valore della voce dell'array (non l'intera riga dell'array completo da declare -p), sarebbe come someArray[3]="abc", e così via ...
Aquarius Power il

1
@Ramiro no. Ho controllato. :)
Matt Komarnicki il

22

ancora più breve usando il punto:

#!/bin/bash
. CONFIG_FILE

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

17
Quando lo si utilizza in uno script, la scorciatoia non è necessaria e potrebbe creare confusione. Perché non usare il sourcecomando completo per chiarire?
Lyle,

2
@Lyle Perché vuoi che il tuo script non si discosti gratuitamente dalla sintassi POSIX portatile quando non è necessario?
triplo il

14

Utilizzare il sourcecomando per importare altri script:

#!/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

Ho lo stesso problema specialmente in caso di sicurezza e ho trovato la soluzione qui .

Il mio problema era che volevo scrivere uno script di distribuzione in bash con un file di configurazione che contenesse un percorso come questo.

################### 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 soluzione esistente consiste nell'utilizzare il comando "SOURCE" e importare il file di configurazione con queste variabili. 'Percorso SOURCE / to / file' Ma questa soluzione presenta alcuni problemi di sicurezza, poiché il file di origine può contenere qualsiasi cosa che uno script Bash può contenere. Ciò crea problemi di sicurezza. Una persona malintenzionata può "eseguire" codice arbitrario quando lo script sta cercando il suo file di configurazione.

Immagina qualcosa del genere:

 ################### 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 ~/*

Per risolvere questo problema, potremmo voler consentire solo i costrutti nel modulo NAME=VALUEin quel file (sintassi di assegnazione variabile) e forse i commenti (anche se tecnicamente, i commenti non sono importanti). Quindi, possiamo controllare il file di configurazione usando il egrepcomando equivalente di grep -E.

Ecco come ho risolto il 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
Non ho verificato il tuo programma di verifica della sintassi per assicurarmi che conti correttamente tutti i casi, ma questa è di gran lunga la migliore idea a causa del problema di sicurezza.
Angelo,

6
Non è abbastanza sicuro, puoi ancora farlo CMD="$(rm -fr ~/*)".
svlasov,

Grazie @svlasov, penso che sia un problema serio, modifico la mia risposta per evitare quel tipo di problema rifiutando i caratteri usati per la sottotitolazione dei comandi come (e `` il finale CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
Erman,

Ancora non abbastanza. foo=bar unleash_viruspuò essere eseguito. Nota foo=bar\ unleash_virus, foo="bar unleash_virus"e foo=bar #unleash_virussono sicuri. Non è facile igienizzare correttamente e non bloccare comunque qualche sintassi innocua, specialmente quando si pensa a ogni possibile quotazione e fuga.
Kamil Maciorowski l'

9

in Bash, per generare l'output di alcuni comandi, anziché un file:

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

riferimento


3

Conversione del file di parametri in variabili di ambiente

Di solito vado sull'analisi anziché sull'approvvigionamento, per evitare la complessità di alcuni artefatti nel mio file. Mi offre anche modi per gestire in modo specifico citazioni e altre cose. Il mio obiettivo principale è quello di mantenere tutto ciò che viene dopo '=' come letterale, anche le doppie virgolette e gli spazi.

#!/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"

Nota il piccolo trucco che ho dovuto fare per considerare il mio testo citato come un singolo parametro con spazio per la mia cntparsfunzione. Era richiesto un ulteriore livello di valutazione. Se non lo facessi, come nell'opzione 2, avrei passato 2 parametri come segue:

  • "value
  • content"

Le doppie virgolette durante l'esecuzione del comando mantengono le virgolette doppie dal file dei parametri. Quindi anche la terza opzione fallisce.

L'altra opzione sarebbe ovviamente quella di non semplicemente fornire le variabili tra virgolette doppie, come nell'opzione 4, e quindi solo per assicurarsi di citarle quando necessario.

Solo qualcosa da tenere a mente.

Ricerca in tempo reale

Un'altra cosa che mi piace fare è fare una ricerca in tempo reale, evitando l'uso delle variabili d'ambiente:

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}"

Non è il più efficiente, ma con file più piccoli funziona in modo molto pulito.


2

Se le variabili vengono generate e non salvate in un file, non è possibile reindirizzarle source. Il modo ingannevolmente semplice per farlo è questo:

some command | xargs

-1

Lo script contenente variabili può essere eseguito importato usando bash. Considera lo script-variable.sh

#!/bin/sh
scr-var=value

Considera lo script effettivo in cui verrà utilizzata la variabile:

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

Questo non funziona, eseguirà lo script Bash in un sottoprocesso e quindi perderà qualsiasi ambiente (comprese le variabili) che ha creato durante la sua vita. Inoltre src-varnon è un identificatore valido.
triplo il

-1

Per prevenire conflitti di denominazione, importare solo le variabili necessarie:

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

    echo $(
        source "${file}";
        eval echo \$\{${variable}\}
    )
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.