Como referenciar um arquivo para variáveis ​​usando o Bash?

151

Quero chamar um arquivo de configurações para uma variável, como posso fazer isso no bash?

Portanto, o arquivo de configurações definirá as variáveis ​​(por exemplo: CONFIG.FILE):

production="liveschool_joe"
playschool="playschool_joe"

E o script usará essas variáveis ​​nele

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

Como posso fazer com que o bash faça algo assim? Vou ter que usar awk / sed etc ...?

edumike
fonte

Respostas:

241

A resposta curta

Use o sourcecomando


Um exemplo usando source

Por exemplo:

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

Observe que a saída sh ./script.shdeste exemplo é:

~$ sh ./script.sh 
playschool_joe
liveschool_joe

Isso ocorre porque o sourcecomando realmente executa o programa. Tudo config.shé executado.


Outra maneira

Você pode usar o exportcomando interno e obter e definir "variáveis ​​de ambiente" também pode fazer isso.

Em execução exporte echo $ENVdeve ser tudo o que você precisa saber sobre como acessar variáveis. O acesso às variáveis ​​de ambiente é feito da mesma maneira que uma variável local.

Para configurá-los, diga:

export variable=value

na linha de comando. Todos os scripts poderão acessar esse valor.

Esdras
fonte
O config.sh deve ter permissão de execução para que isso funcione?
Ramiro
2
Existe uma maneira de usar sourcecanalizando o conteúdo em vez de fornecer um arquivo? Como some command | sourcenão funciona ...
Elliot Chance
1
Deixa pra lá, encontrei a solução e a publiquei para outras pessoas.
Elliot Possibilidade
e para restaurar matrizes, você tem que armazenar cada valor de entrada de gama separatedly (não a única linha completa gama de declare -p), seria como someArray[3]="abc", e assim por diante ...
Aquarius Poder
1
@ Ramiro não, não. Eu chequei. :)
Matt Komarnicki
22

ainda mais curto usando o ponto:

#!/bin/bash
. CONFIG_FILE

sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool
wnrph
fonte
17
Ao usar isso em um script, a abreviação é desnecessária e pode ser confusa. Por que não usar o sourcecomando completo para deixar claro?
Lyle
2
@Lyle Porque você deseja que seu script não se desvie gratuitamente da sintaxe portátil POSIX quando você não precisa?
Tripleee
14

Use o sourcecomando para importar outros 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
Daniel
fonte
12

Eu tenho o mesmo problema, especialmente em casos de segurança e encontrei a solução aqui .

Meu problema era que, eu queria escrever um script de implantação no bash com um arquivo de configuração que contenha algum caminho como este.

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

Uma solução existente consiste no uso do comando "SOURCE" e importa o arquivo de configuração com essas variáveis. 'SOURCE path / to / file' Mas esta solução tem algum problema de segurança, porque o arquivo de origem pode conter qualquer coisa que um script do Bash possa conter. Isso cria problemas de segurança. Uma pessoa malicicios pode "executar" código arbitrário quando seu script estiver fornecendo seu arquivo de configuração.

Imagine algo como isto:

 ################### 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 isso, convém permitir apenas construções no formulário NAME=VALUEdesse arquivo (sintaxe da atribuição de variável) e talvez comentários (embora tecnicamente, os comentários não sejam importantes). Portanto, podemos verificar o arquivo de configuração usando o egrepcomando equivalente a grep -E.

Foi assim que resolvi o 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
Erman
fonte
1
Não verifiquei seu verificador de sintaxe para garantir que ele responda a todos os casos corretamente, mas essa é de longe a melhor ideia por causa do problema de segurança.
Angelo
6
Isso não é seguro o suficiente, você ainda pode fazer CMD="$(rm -fr ~/*)".
svlasov
Obrigado @svlasov, acho que é um problema sério, edito minha resposta para evitar esse tipo de problema, rejeitando os caracteres usados ​​para a legenda de comandos como (e `` the final CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
Erman
Ainda não é suficiente. foo=bar unleash_viruspode ser executado. Nota foo=bar\ unleash_virus, foo="bar unleash_virus"e foo=bar #unleash_virussão seguros. Não é fácil higienizar adequadamente e não bloquear nenhuma sintaxe inofensiva, especialmente quando você pensa em todas as citações e escapamentos possíveis.
Kamil Maciorowski
9

no Bash, para obter a saída de algum comando, em vez de um arquivo:

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

referência

zhazha
fonte
3

Convertendo arquivo de parâmetro em variáveis ​​de ambiente

Normalmente, procuro analisar em vez de procurar, para evitar complexidades de certos artefatos no meu arquivo. Também me oferece maneiras de lidar com citações e outras coisas especialmente. Meu principal objetivo é manter o que vem depois do '=' como literal, mesmo as aspas duplas e os espaços.

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

Observe o pequeno truque que eu tive que fazer para considerar meu texto citado como um único parâmetro com espaço para minha cntparsfunção. Havia um nível extra de avaliação necessário. Se eu não fizesse isso, como na Opção 2, eu teria passado 2 parâmetros da seguinte maneira:

  • "value
  • content"

A citação dupla durante a execução do comando faz com que as aspas duplas do arquivo de parâmetros sejam mantidas. Portanto, a terceira opção também falha.

A outra opção seria, obviamente, simplesmente não fornecer variáveis ​​entre aspas duplas, como na Opção 4, e apenas garantir que você as cite quando necessário.

Apenas algo para ter em mente.

Pesquisa em tempo real

Outra coisa que gosto de fazer é fazer uma pesquisa em tempo real, evitando o uso de variáveis ​​de 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}"

Não é o mais eficiente, mas com arquivos menores funciona muito bem.

YoYo
fonte
2

Se as variáveis ​​estiverem sendo geradas e não salvas em um arquivo, você não poderá inseri-las source. A maneira enganosamente simples de fazer isso é:

some command | xargs
Elliot Chance
fonte
-1

O script que contém variáveis ​​pode ser executado importado usando o bash. Considere o script-variable.sh

#!/bin/sh
scr-var=value

Considere o script real em que a variável será usada:

 #!/bin/sh
 bash path/to/script-variable.sh
 echo "$scr-var"
Rohith
fonte
Isso não funciona, ele executará o script Bash em um subprocesso e perderá qualquer ambiente (incluindo variáveis) criado durante sua vida útil. Também src-varnão é um identificador válido.
Tripleee
-1

Para evitar conflitos de nomenclatura, importe apenas as variáveis ​​necessárias:

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

    echo $(
        source "${file}";
        eval echo \$\{${variable}\}
    )
}
Alberto Salvia Novella
fonte