Jak odwołać się do pliku dla zmiennych za pomocą Bash?

151

Chcę wywołać plik ustawień dla zmiennej, jak mogę to zrobić w bash?

Zatem plik ustawień będzie definiował zmienne (np .: PLIK KONFIGURACJI):

production="liveschool_joe"
playschool="playschool_joe"

A skrypt użyje w nim tych zmiennych

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

Jak mogę zmusić bash do zrobienia czegoś takiego? Czy będę musiał używać awk / sed etc ...?

edumike
źródło

Odpowiedzi:

241

Krótka odpowiedź

Użyj sourcepolecenia.


Przykład użycia source

Na przykład:

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

Zwróć uwagę, że dane wyjściowe z sh ./script.shtego przykładu to:

~$ sh ./script.sh 
playschool_joe
liveschool_joe

Dzieje się tak, ponieważ sourcepolecenie faktycznie uruchamia program. Wszystko config.shjest wykonane.


Inny sposób

Możesz użyć wbudowanego exportpolecenia, a pobranie i ustawienie „zmiennych środowiskowych” również może to osiągnąć.

Działa exporti echo $ENVpowinno być wszystkim, co musisz wiedzieć o dostępie do zmiennych. Dostęp do zmiennych środowiskowych odbywa się w taki sam sposób, jak do zmiennej lokalnej.

Aby je ustawić, powiedz:

export variable=value

w wierszu poleceń. Wszystkie skrypty będą miały dostęp do tej wartości.

Ezra
źródło
Czy config.sh musi mieć uprawnienia do wykonywania, aby to działało?
Ramiro
2
Czy istnieje sposób użycia sourceprzez potokowanie zawartości zamiast dostarczania pliku? Jak some command | sourcenie działa ...
Elliot Chance,
1
Nieważne, znalazłem rozwiązanie i wysłałem je innym.
Elliot Chance
i aby przywrócić tablice, musisz przechowywać każdą wartość wpisu tablicy osobno (nie całą pojedynczą linię tablicy declare -p), tak by wyglądało someArray[3]="abc", i tak dalej ...
Aquarius Power
1
@Ramiro no, nie ma. Sprawdziłem. :)
Matt Komarnicki
22

jeszcze krócej za pomocą kropki:

#!/bin/bash
. CONFIG_FILE

sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool
wnrph
źródło
17
Używając tego w skrypcie, skrót jest niepotrzebny i może być mylący. Dlaczego nie użyć pełnego sourcepolecenia, aby było jasne?
Lyle
2
@Lyle Ponieważ chcesz, aby Twój skrypt nie odbiegał w nieuzasadniony sposób od przenośnej składni POSIX, kiedy nie musisz tego robić?
tripleee
14

Użyj sourcepolecenia, aby zaimportować inne skrypty:

#!/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
źródło
12

Mam ten sam problem szczególnie w przypadku bezpieczeństwa i tutaj znalazłem rozwiązanie .

Mój problem polegał na tym, że chciałem napisać skrypt wdrożeniowy w bash z plikiem konfiguracyjnym, który zawiera taką ścieżkę jak ta.

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

Istniejące rozwiązanie polega na użyciu polecenia „SOURCE” i zaimportowaniu pliku konfiguracyjnego z tymi zmiennymi. „ŹRÓDŁOWA ścieżka / do / pliku” Ale to rozwiązanie ma pewien problem z bezpieczeństwem, ponieważ plik źródłowy może zawierać wszystko, co może zawierać skrypt Bash. To stwarza problemy z bezpieczeństwem. Osoba malicicios może „wykonać” dowolny kod, gdy skrypt pozyskuje swój plik konfiguracyjny.

Wyobraź sobie coś takiego:

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

Aby rozwiązać ten problem, możemy chcieć zezwolić tylko na konstrukcje w formie NAME=VALUEw tym pliku (składnia przypisania zmiennych) i być może komentarze (chociaż technicznie komentarze są nieważne). Możemy więc sprawdzić plik konfiguracyjny za pomocą egrepodpowiednika polecenia grep -E.

W ten sposób rozwiązałem problem.

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
źródło
1
Nie zweryfikowałem Twojego narzędzia do sprawdzania składni, aby upewnić się, że poprawnie uwzględnia wszystkie przypadki, ale jest to zdecydowanie najlepszy pomysł ze względu na problem z bezpieczeństwem.
Angelo
6
To nie jest wystarczająco bezpieczne, nadal możesz to zrobić CMD="$(rm -fr ~/*)".
svlasov
Dzięki @svlasov, myślę, że to poważny problem, edytuję swoją odpowiedź, aby uniknąć tego typu problemu, odrzucając znaki używane do zastępowania poleceń, takie jak (i `` finał CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
Erman
Wciąż za mało. foo=bar unleash_virusmożna wykonać. Uwaga foo=bar\ unleash_virus, foo="bar unleash_virus"i foo=bar #unleash_virussą bezpieczne. Nie jest łatwo prawidłowo oczyścić i tak nie blokować jakiejś nieszkodliwej składni, zwłaszcza gdy myślisz o każdym możliwym cytowaniu i ucieczce.
Kamil Maciorowski
9

w Bash, aby pobrać dane wyjściowe polecenia, zamiast pliku:

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

odniesienie

zhazha
źródło
3

Konwersja pliku parametrów na zmienne środowiskowe

Zwykle zajmuję się analizowaniem zamiast pozyskiwaniem, aby uniknąć złożoności niektórych artefaktów w moim pliku. Oferuje mi również sposoby specjalnego traktowania cytatów i innych rzeczy. Moim głównym celem jest zachowanie literału po znaku „=”, nawet podwójnych cudzysłowów i spacji.

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

Zwróć uwagę na małą sztuczkę, którą musiałem zrobić, aby potraktować mój cytowany tekst jako pojedynczy parametr ze spacją do mojej cntparsfunkcji. Wymagany był jeden dodatkowy poziom oceny. Gdybym tego nie zrobił, jak w Opcji 2, przekazałbym 2 parametry w następujący sposób:

  • "value
  • content"

Podwójne cudzysłowy podczas wykonywania polecenia powoduje zachowanie podwójnych cudzysłowów z pliku parametrów. Dlatego trzecia opcja również zawodzi.

Inną opcją byłoby oczywiście po prostu nie podawanie zmiennych w podwójnych cudzysłowach, jak w opcji 4, a następnie po prostu upewnienie się, że w razie potrzeby zacytujesz je.

Tylko coś do zapamiętania.

Wyszukiwanie w czasie rzeczywistym

Inną rzeczą, którą lubię robić, jest wyszukiwanie w czasie rzeczywistym, unikając użycia zmiennych środowiskowych:

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

Nie jest to najbardziej wydajne, ale przy mniejszych plikach działa bardzo czysto.

YoYo
źródło
2

Jeśli zmienne są generowane i nie są zapisywane w pliku, nie można ich przesłać potokowo source. Pozornie prosty sposób na zrobienie tego jest następujący:

some command | xargs
Elliot Chance
źródło
-1

Skrypt zawierający zmienne można wykonać zaimportować za pomocą basha. Rozważmy skrypt-variable.sh

#!/bin/sh
scr-var=value

Rozważ rzeczywisty skrypt, w którym zmienna będzie używana:

 #!/bin/sh
 bash path/to/script-variable.sh
 echo "$scr-var"
Rohith
źródło
To nie działa, uruchomi skrypt Bash w podprocesie, a następnie utraci środowisko (w tym zmienne), które utworzył podczas jego życia. Nie src-varjest też prawidłowym identyfikatorem.
tripleee
-1

Aby zapobiec konfliktom nazw, importuj tylko te zmienne, których potrzebujesz:

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

    echo $(
        source "${file}";
        eval echo \$\{${variable}\}
    )
}
Alberto Salvia Novella
źródło