Як посилатися на файл для змінних за допомогою Bash?


151

Я хочу викликати файл налаштувань змінної, як це зробити в 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

Як я можу змусити башти зробити щось подібне? Чи доведеться мені використовувати awk / sed тощо ...?

Відповіді:


241

Коротка відповідь

Використовуйте 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

у командному рядку. Усі сценарії зможуть отримати доступ до цього значення.


Повинен config.sh виконати дозвіл, щоб це працювало?
Раміро

2
Чи є спосіб використання source, перекладаючи вміст, а не надаючи файл? Начебто some command | sourceне працює ...
Шанс Елліот

1
Не маючи на увазі, я знайшов рішення і розмістив його для інших.
Шанс Елліот

і щоб відновити масиви, потрібно зберігати кожне значення запису масиву окремо (не єдиний рядок масиву з declare -p), як someArray[3]="abc", і так далі ...
Водолій 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

17
Використовуючи це в сценарії, стенограма непотрібна і може заплутати. Чому б не використати повну sourceкоманду, щоб зрозуміти це?
Лайл

2
@Lyle Тому що ви хочете, щоб ваш скрипт безоплатно відходив від портативного синтаксису POSIX, коли цього не потрібно?
трійка

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" та імпортування файлу config з цією змінною. 'Шлях Джерела / до / файлу' Але в цьому рішенні є певна проблема безпеки, тому що джерело файлу може містити все, що вміє сценарій 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"; 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, я пройшов би два параметри так:

  • "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. Розглянемо script-variable.sh

#!/bin/sh
scr-var=value

Розглянемо власне сценарій, де буде використана змінна:

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

Це не працює, він запустить сценарій Bash у підпроцесі, а потім втратить будь-яке середовище (включаючи змінні), створене протягом його життя. Також src-varне є дійсним ідентифікатором.
трійка

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.