Comment référencer un fichier pour des variables en utilisant Bash?


152

Je veux appeler un fichier de paramètres pour une variable, comment puis-je faire cela dans bash?

Ainsi, le fichier de paramètres définira les variables (par exemple: CONFIG.FILE):

production="liveschool_joe"
playschool="playschool_joe"

Et le script utilisera ces variables dedans

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

Comment puis-je faire en sorte que Bash fasse quelque chose comme ça? Dois-je utiliser awk / sed etc ...?

Réponses:


243

La réponse courte

Utilisez la sourcecommande.


Un exemple utilisant source

Par exemple:

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

Notez que la sortie de sh ./script.shcet exemple est:

~$ sh ./script.sh 
playschool_joe
liveschool_joe

C'est parce que la sourcecommande exécute réellement le programme. Tout config.shest exécuté.


Autrement

Vous pouvez utiliser la exportcommande intégrée et obtenir et définir des "variables d'environnement" peuvent également accomplir cela.

Exécuter exportet echo $ENVdevrait être tout ce que vous devez savoir sur l'accès aux variables. L'accès aux variables d'environnement se fait de la même manière qu'une variable locale.

Pour les définir, dites:

export variable=value

sur la ligne de commande. Tous les scripts pourront accéder à cette valeur.


Config.sh doit-il avoir l'autorisation d'exécution pour que cela fonctionne?
Ramiro

2
Existe-t-il un moyen d'utiliser sourceen canalisant le contenu plutôt qu'en fournissant un fichier? Like some command | sourcedoes not work ...
Elliot Chance

1
Peu importe, j'ai trouvé la solution et l'ai postée pour d'autres.
Elliot Chance

et pour restaurer des tableaux, vous devez stocker chaque valeur d'entrée de tableau séparément (pas la ligne complète du tableau à partir de declare -p), ce serait comme someArray[3]="abc", et ainsi de suite ...
Aquarius Power

1
@Ramiro non, non. J'ai vérifié. :)
Matt Komarnicki

22

encore plus court en utilisant le point:

#!/bin/bash
. CONFIG_FILE

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

17
Lorsque vous utilisez ceci dans un script, le raccourci est inutile et peut prêter à confusion. Pourquoi ne pas utiliser la sourcecommande complète pour le rendre clair?
Lyle

2
@Lyle Parce que vous voulez que votre script ne s'écarte pas gratuitement de la syntaxe POSIX portable lorsque vous n'en avez pas besoin?
tripleee

14

Utilisez la sourcecommande pour importer d'autres 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

J'ai le même problème spécialement en cas de sécurité et j'ai trouvé la solution ici .

Mon problème était que je voulais écrire un script de déploiement en bash avec un fichier de configuration contenant un chemin comme celui-ci.

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

Une solution existante consiste à utiliser la commande "SOURCE" et à importer le fichier de configuration avec ces variables. 'SOURCE path / to / file' Mais cette solution présente un problème de sécurité, car le fichier source peut contenir tout ce qu'un script Bash peut. Cela crée des problèmes de sécurité. Une personne malicieuse peut "exécuter" du code arbitraire lorsque votre script recherche son fichier de configuration.

Imaginez quelque chose comme ça:

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

Pour résoudre ce problème, nous pourrions vouloir autoriser uniquement les constructions sous la forme NAME=VALUEde ce fichier (syntaxe d'attribution de variable) et peut-être les commentaires (bien que techniquement, les commentaires ne soient pas importants). Ainsi, nous pouvons vérifier le fichier de configuration en utilisant une egrepcommande équivalente à grep -E.

C'est ainsi que j'ai résolu le problème.

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
Je n'ai pas vérifié votre vérificateur de syntaxe pour m'assurer qu'il tient correctement compte de tous les cas, mais c'est de loin la meilleure idée en raison du problème de sécurité.
Angelo

6
Ce n'est pas assez sûr, vous pouvez toujours le faire CMD="$(rm -fr ~/*)".
svlasov

Merci @svlasov, je pense que c'est un problème sérieux, je modifie ma réponse pour éviter ce type de problème en rejetant les caractères utilisés pour la subtitution de commande comme (et `` la finale CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
Erman

Ce n'est toujours pas suffisant. foo=bar unleash_viruspeut être exécuté. Remarque foo=bar\ unleash_virus, foo="bar unleash_virus"et foo=bar #unleash_virussont sûrs. Il n'est pas facile de nettoyer correctement et de ne pas bloquer de toute façon une syntaxe inoffensive, surtout quand on pense à toutes les citations et échappements possibles.
Kamil Maciorowski

9

dans Bash, pour générer la sortie d'une commande, au lieu d'un fichier:

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

référence


3

Conversion d'un fichier de paramètres en variables d'environnement

Habituellement, je procède à l'analyse au lieu de l'approvisionnement, pour éviter la complexité de certains artefacts dans mon fichier. Il me propose également des moyens de gérer spécialement les devis et autres choses. Mon objectif principal est de conserver tout ce qui vient après le «=» comme un littéral, même les guillemets et les espaces.

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

Notez la petite astuce que j'ai dû faire pour considérer mon texte cité comme un seul paramètre avec un espace pour ma cntparsfonction. Il y avait un niveau d'évaluation supplémentaire requis. Si je ne faisais pas cela, comme dans l'option 2, j'aurais passé 2 paramètres comme suit:

  • "value
  • content"

Les guillemets doubles lors de l'exécution de la commande entraînent la conservation des guillemets doubles du fichier de paramètres. Par conséquent, la 3e option échoue également.

L'autre option serait bien sûr de simplement ne pas fournir de variables entre guillemets, comme dans l'option 4, et ensuite de simplement vous assurer de les citer en cas de besoin.

Juste quelque chose à garder à l'esprit.

Recherche en temps réel

Une autre chose que j'aime faire est de faire une recherche en temps réel, en évitant l'utilisation de variables d'environnement:

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

Pas le plus efficace, mais avec des fichiers plus petits fonctionne très proprement.


2

Si les variables sont générées et non enregistrées dans un fichier, vous ne pouvez pas les diriger vers source. La façon trompeusement simple de le faire est la suivante:

some command | xargs

-1

Le script contenant des variables peut être exécuté importé à l'aide de bash. Considérez le script-variable.sh

#!/bin/sh
scr-var=value

Considérez le script réel où la variable sera utilisée:

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

Cela ne fonctionne pas, il exécutera le script Bash dans un sous-processus, puis perdra tout environnement (y compris les variables) créé au cours de sa vie. N'est src-varpas non plus un identifiant valide.
tripleee

-1

Pour éviter les conflits de noms, importez uniquement les variables dont vous avez besoin:

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

    echo $(
        source "${file}";
        eval echo \$\{${variable}\}
    )
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.