Как ссылаться на файл для переменных, используя Bash?

152

Я хочу вызвать файл настроек для переменной, как я могу это сделать в bash?

Таким образом, файл настроек будет определять переменные (например: CONFIG.FILE):

production="liveschool_joe"
playschool="playschool_joe"

И скрипт будет использовать эти переменные в нем

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

Как я могу заставить bash сделать что-то подобное? Должен ли я использовать awk / sed и т. Д.?

edumike
источник

Ответы:

243

Краткий ответ

Используйте sourceкоманду.


Пример использования source

Например:

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

Обратите внимание, что вывод sh ./script.shв этом примере:

~$ sh ./script.sh 
playschool_joe
liveschool_joe

Это потому, что sourceкоманда на самом деле запускает программу. Все config.shвыполнено.


По-другому

Вы можете использовать встроенную exportкоманду, и получение и установка «переменных среды» также могут это сделать.

Запуск exportи echo $ENVдолжно быть все, что вам нужно знать о доступе к переменным. Доступ к переменным окружения осуществляется так же, как и к локальной переменной.

Чтобы установить их, скажите:

export variable=value

в командной строке. Все сценарии смогут получить доступ к этому значению.

Ezra
источник
Должен ли config.sh иметь разрешение на выполнение, чтобы это работало?
Рамиро
2
Есть ли способ использовать source, передавая содержимое, а не предоставляя файл? Вроде some command | sourceне работает ...
Эллиот Шанс
1
Неважно, я нашел решение и разместил его для других.
Эллиот Шанс
и чтобы восстановить массивы, вы должны хранить каждое значение записи массива отдельно (а не полный массив из одной строки declare -p), как someArray[3]="abc"и так далее ...
Aquarius Power
1
@ Рамиро нет, это не так. Я проверил. :)
Мэтт Комарницкий
22

еще короче используя точку:

#!/bin/bash
. CONFIG_FILE

sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool
wnrph
источник
17
При использовании этого в сценарии сокращение не требуется и может привести к путанице. Почему бы не использовать полную sourceкоманду, чтобы прояснить ситуацию?
Лайл
2
@Lyle Потому что вы хотите, чтобы ваш скрипт не отклонялся безвозмездно от переносимого синтаксиса POSIX, когда вам это не нужно?
tripleee
14

Используйте sourceкоманду для импорта других скриптов:

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

У меня такая же проблема, особенно в плане безопасности, и я нашел решение здесь .

Моя проблема заключалась в том, что я хотел написать сценарий развертывания на bash с файлом конфигурации, который содержал бы такой путь, как этот.

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

Существующее решение состоит из использования команды «SOURCE» и импорта файла конфигурации с этими переменными. 'SOURCE путь / к / файлу' Но у этого решения есть некоторая проблема безопасности, потому что исходный файл может содержать все, что может сценарий Bash. Это создает проблемы безопасности. Специалист по malicicios может «выполнить» произвольный код, когда ваш скрипт использует свой конфигурационный файл.

Представьте себе что-то вроде этого:

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

Чтобы решить эту проблему, мы можем захотеть разрешить только конструкции в форме NAME=VALUEв этом файле (синтаксис присваивания переменных) и, возможно, комментарии (хотя технически комментарии не важны). Итак, мы можем проверить файл конфигурации с помощью egrepкоманды, эквивалентной grep -E.

Вот как я должен решить проблему.

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
Я не проверил вашу проверку синтаксиса, чтобы убедиться, что она правильно учитывает все случаи, но это лучшая идея из-за проблем безопасности.
Анджело
6
Это недостаточно безопасно, вы все еще можете сделать CMD="$(rm -fr ~/*)".
svlasov
Спасибо @svlasov, я думаю, что это серьезная проблема, я редактирую свой ответ, чтобы избежать проблем такого типа, отвергая символы, используемые для подстановки команд, такие как (и `` `финалCONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
Эрман
Все еще недостаточно. foo=bar unleash_virusможет быть выполнен Обратите внимание foo=bar\ unleash_virus, foo="bar unleash_virus"и foo=bar #unleash_virusв безопасности. Нелегко правильно дезинфицировать и не блокировать какой-то безобидный синтаксис, особенно когда вы думаете о всевозможных цитировании и экранировании.
Камиль Мачоровски
9

в Bash, чтобы получить вывод какой-то команды вместо файла:

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

ссылка

Жажа
источник
3

Преобразование файла параметров в переменные окружения

Обычно я занимаюсь разбором вместо поиска, чтобы избежать сложностей определенных артефактов в моем файле. Он также предлагает мне способы специально обрабатывать цитаты и другие вещи. Моя главная цель - сохранить все, что следует после «=» в качестве литерала, даже двойные кавычки и пробелы.

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

Обратите внимание на небольшую хитрость, которую я должен был сделать, чтобы рассмотреть мой цитируемый текст как один параметр с пробелом в моей cntparsфункции. Был один дополнительный уровень оценки требуется. Если бы я не сделал этого, как в варианте 2, я бы передал 2 параметра следующим образом:

  • "value
  • content"

Двойные кавычки во время выполнения команды приводят к сохранению двойных кавычек из файла параметров. Следовательно, 3-й вариант также не работает.

Другой вариант, разумеется, состоит в том, чтобы просто не указывать переменные в двойных кавычках, как в варианте 4, а затем просто убедиться, что вы их цитируете при необходимости.

Просто что-то иметь в виду.

Поиск в реальном времени

Еще мне нравится делать поиск в реальном времени, избегая использования переменных окружения:

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

Не самый эффективный, но с небольшими файлами работает очень чисто.

Йо Йо
источник
2

Если переменные генерируются и не сохраняются в файл, вы не можете передать их в source. Обманчиво простой способ сделать это так:

some command | xargs
Эллиот Шанс
источник
-1

Сценарий, содержащий переменные, может быть выполнен импортированным с использованием bash. Рассмотрим скрипт-variable.sh

#!/bin/sh
scr-var=value

Рассмотрим реальный скрипт, в котором будет использоваться переменная:

 #!/bin/sh
 bash path/to/script-variable.sh
 echo "$scr-var"
Rohith
источник
Это не работает, он запустит скрипт Bash в подпроцессе, а затем потеряет любую среду (включая переменные), созданную им при жизни. Также src-varне является действительным идентификатором.
tripleee
-1

Для предотвращения конфликтов имен импортируйте только те переменные, которые вам нужны:

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

    echo $(
        source "${file}";
        eval echo \$\{${variable}\}
    )
}
Альберто Сальвия Новелла
источник