Szablony Bash: jak budować pliki konfiguracyjne z szablonów za pomocą Bash?

Piszę skrypt do automatyzacji tworzenia plików konfiguracyjnych dla Apache i PHP dla własnego serwera www. Nie chcę używać żadnych GUI, takich jak CPanel lub ISPConfig.

Mam kilka szablonów plików konfiguracyjnych Apache i PHP. Skrypt Bash musi odczytywać szablony, zastępować zmienne i wyprowadzać przetworzone szablony do jakiegoś folderu. Jak najlepiej to zrobić? Mogę wymyślić kilka sposobów. Który z nich jest najlepszy lub może być kilka lepszych sposobów, aby to zrobić? Chcę zrobić to w czystej Bash (jest to łatwe na przykład w PHP)

1) Jak zastąpić symbole zastępcze ${} w pliku tekstowym?

Szablon.txt:

the number is ${i}
the word is ${word}

Script.sh:

#!/bin/sh

#set variables
i=1
word="dog"
#read in template one line at the time, and replace variables
#(more natural (and efficient) way, thanks to Jonathan Leffler)
while read line
do
    eval echo "$line"
done < "./template.txt"

BTW, jak przekierować wyjście do zewnętrznego pliku tutaj? Czy muszę czegoś unikać, jeśli zmienne zawierają, powiedzmy, cudzysłowy?

2) Użycie cat & sed do zastąpienia każdej zmiennej jej wartością:

Podany szablon.txt:

The number is ${i}
The word is ${word}

Polecenie:

cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"

Wydaje mi się źle z powodu potrzeby aby uniknąć wielu różnych symboli i wielu zmiennych linia będzie zbyt długa.

Czy możesz wymyślić jakieś inne eleganckie i bezpieczne rozwiązanie?
Author: Community, 2010-05-26

21 answers

Możesz użyć tego:

perl -p -i -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg' < template.txt

Zastąpienie wszystkich łańcuchów ${...} odpowiednimi zmiennymi środowiska (nie zapomnij wyeksportować ich przed uruchomieniem tego skryptu).

Dla czystego Basha powinno to działać (zakładając, że zmienne nie zawierają ${...} ciągi):

#!/bin/bash
while read -r line ; do
    while [[ "$line" =~ (\$\{[a-zA-Z_][a-zA-Z_0-9]*\}) ]] ; do
        LHS=${BASH_REMATCH[1]}
        RHS="$(eval echo "\"$LHS\"")"
        line=${line//$LHS/$RHS}
    done
    echo "$line"
done

. Rozwiązanie, które nie zawiesza się, jeśli RHS odwołuje się do jakiejś zmiennej, która odwołuje się do siebie:

#!/bin/bash
line="$(cat; echo -n a)"
end_offset=${#line}
while [[ "${line:0:$end_offset}" =~ (.*)(\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})(.*) ]] ; do
    PRE="${BASH_REMATCH[1]}"
    POST="${BASH_REMATCH[4]}${line:$end_offset:${#line}}"
    VARNAME="${BASH_REMATCH[3]}"
    eval 'VARVAL="$'$VARNAME'"'
    line="$PRE$VARVAL$POST"
    end_offset=${#PRE}
done
echo -n "${line:0:-1}"

WARNING: Nie wiem jak poprawnie obsłużyć input z NULs w bash lub preserve ilość kończących się nowych linii. Ostatni wariant jest przedstawiony tak, ponieważ "love" Binary input:

  1. read zinterpretuje ukośniki.
  2. read -r nie zinterpretuje ukośników wstecznych, ale i tak upuści ostatnią linię, jeśli nie zakończy się nową linią.
  3. "$(…)" usunie tyle nowych znaków, ile jest obecnych, więc kończę z ; echo -n a i użyję echo -n "${line:0:-1}": to usunie ostatni znak (który jest a) i zachowa tyle nowych znaków, ile było na wejściu (w tym nie).
 47
Author: ZyX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-18 22:23:43

Try envsubst

FOO=foo
BAR=bar
export FOO BAR

envsubst <<EOF
FOO is $FOO
BAR is $BAR
EOF
 91
Author: yottatsa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-15 12:48:40

Envsubst był dla mnie nowy. Fantastycznie.

Dla przypomnienia, użycie heredoc jest świetnym sposobem na szablon pliku conf.

STATUS_URI="/hows-it-goin";  MONITOR_IP="10.10.2.15";

cat >/etc/apache2/conf.d/mod_status.conf <<EOF
<Location ${STATUS_URI}>
    SetHandler server-status
    Order deny,allow
    Deny from all
    Allow from ${MONITOR_IP}
</Location>
EOF
 34
Author: Dan Garthwaite,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-17 13:33:14

Zgadzam się z używaniem sed: jest to najlepsze narzędzie do wyszukiwania/zastępowania. Oto moje podejście:

$ cat template.txt
the number is ${i}
the dog's name is ${name}

$ cat replace.sed
s/${i}/5/
s/${name}/Fido/

$ sed -f replace.sed template.txt > out.txt

$ cat out.txt
the number is 5
the dog's name is Fido
 29
Author: Hai Vu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-26 18:13:52

Myślę, że eval działa naprawdę dobrze. Obsługuje szablony z przerwami liniowymi, białymi spacjami i wszelkiego rodzaju materiałami bash. Jeśli masz pełną kontrolę nad samymi szablonami oczywiście:

$ cat template.txt
variable1 = ${variable1}
variable2 = $variable2
my-ip = \"$(curl -s ifconfig.me)\"

$ echo $variable1
AAA
$ echo $variable2
BBB
$ eval "echo \"$(<template.txt)\"" 2> /dev/null
variable1 = AAA
variable2 = BBB
my-ip = "11.22.33.44"

Tę metodę należy oczywiście stosować ostrożnie, ponieważ eval może wykonać dowolny kod. Uruchamianie tego jako root nie wchodzi w grę. Cytaty w szablonie muszą być unikalne, w przeciwnym razie zostaną zjedzone przez eval.

Możesz również użyć tutaj dokumentów, jeśli wolisz cat, Aby echo

$ eval "cat <<< \"$(<template.txt)\"" 2> /dev/null

@plockc napisał rozwiązanie, które pozwala uniknąć problemu z cytowaniem Basha:

$ eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null

Edit: usunięto część o uruchomieniu tego jako root przy użyciu sudo...

Edit: Dodano komentarz o tym, jak należy unikać cytatów, dodano rozwiązanie płockc do miksu!

 16
Author: mogsie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-17 12:41:57

Edycja 6 Stycznia 2017

Musiałem zachować podwójne cudzysłowy w moim pliku konfiguracyjnym, więc podwójne unikanie podwójnych cudzysłowów z sed pomaga:

render_template() {
  eval "echo \"$(sed 's/\"/\\\\"/g' $1)\""
}

Nie mogę myśleć o ciągnięciu nowych linii, ale puste linie pomiędzy są utrzymywane.


Chociaż jest to stary temat, IMO znalazłem bardziej eleganckie rozwiązanie tutaj: http://pempek.net/articles/2013/07/08/bash-sh-as-template-engine/

#!/bin/sh

# render a template configuration file
# expand variables + preserve formatting
render_template() {
  eval "echo \"$(cat $1)\""
}

user="Gregory"
render_template /path/to/template.txt > path/to/configuration_file

Wszystkie napisy dla Grégory Pakosz.

 16
Author: CKK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-06 14:26:43

Mam rozwiązanie bash jak mogsie, ale z heredoc zamiast herestring, aby uniknąć unikania podwójnych cudzysłowów

eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
 14
Author: plockc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-25 16:19:40

Dłuższa, ale solidniejsza wersja zaakceptowanej odpowiedzi:

perl -pe 's;(\\*)(\$([a-zA-Z_][a-zA-Z_0-9]*)|\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})?;substr($1,0,int(length($1)/2)).($2&&length($1)%2?$2:$ENV{$3||$4});eg' template.txt

To rozszerza wszystkie instancje $VAR lub ${VAR} do ich wartości środowiskowych (lub, jeśli są niezdefiniowane, pusty łańcuch).

Poprawnie unika ukośników wstecznych i akceptuje ukośnik wsteczny-escaped $ w celu zahamowania substytucji(w przeciwieństwie do envsubst, który, jak się okazuje, tego nie robi ).

Więc jeśli twoje środowisko to:

FOO=bar
BAZ=kenny
TARGET=backslashes
NOPE=engi

A Twój szablon to:

Two ${TARGET} walk into a \\$FOO. \\\\
\\\$FOO says, "Delete C:\\Windows\\System32, it's a virus."
$BAZ replies, "\${NOPE}s."

The wynik będzie:

Two backslashes walk into a \bar. \\
\$FOO says, "Delete C:\Windows\System32, it's a virus."
kenny replies, "${NOPE}s."

Jeśli chcesz tylko uniknąć ukośników przed $ (możesz napisać "C:\Windows\System32" W szablonie bez zmian), użyj tej nieco zmodyfikowanej wersji:

perl -pe 's;(\\*)(\$([a-zA-Z_][a-zA-Z_0-9]*)|\$\{([a-zA-Z_][a-zA-Z_0-9]*)\});substr($1,0,int(length($1)/2)).(length($1)%2?$2:$ENV{$3||$4});eg' template.txt
 9
Author: Stuart P. Bentley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-25 17:57:33

Zrobiłbym to w ten sposób, prawdopodobnie mniej wydajny, ale łatwiejszy do odczytania / utrzymania.

TEMPLATE='/path/to/template.file'
OUTPUT='/path/to/output.file'

while read LINE; do
  echo $LINE |
  sed 's/VARONE/NEWVALA/g' |
  sed 's/VARTWO/NEWVALB/g' |
  sed 's/VARTHR/NEWVALC/g' >> $OUTPUT
done < $TEMPLATE
 8
Author: Craig552uk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-28 11:07:05

Jeśli chcesz użyć szablonów Jinja2 , zobacz ten projekt: j2cli.

Obsługuje:

  • szablony z plików JSON, ini, YAML i strumieni wejściowych
  • Tworzenie szablonów ze zmiennych środowiskowych
 6
Author: kolypto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-25 15:16:58

Biorąc odpowiedź od ZyX używając czystego Basha, ale z dopasowaniem regex w Nowym stylu i pośrednim podstawianiem parametrów staje się:

#!/bin/bash
regex='\$\{([a-zA-Z_][a-zA-Z_0-9]*)\}'
while read line; do
    while [[ "$line" =~ $regex ]]; do
        param="${BASH_REMATCH[1]}"
        line=${line//${BASH_REMATCH[0]}/${!param}}
    done
    echo $line
done
 5
Author: wich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-22 14:17:09

Jeśli używasz Perl jest opcją i jesteś zadowolony z bazowania rozszerzeń na środowisko zmienne tylko (W przeciwieństwie do wszystkich Shell zmienne), rozważmy solidną odpowiedź Stuarta P. Bentleya.

Ta odpowiedź ma na celu dostarczenie tylko bash rozwiązanie , które-pomimo użycia eval - powinno być bezpieczne w użyciu .

Cele to:

  • wsparcie zarówno ${name} jak i $name odniesienia do zmiennych.
  • Zapobiegaj wszelkim innym rozszerzeniom:
    • command substitutions ($(...) and legacy syntax `...`)
    • podstawienia arytmetyczne ($((...)) i składnia dziedziczenia $[...]).
  • umożliwiają selektywne tłumienie rozszerzalności zmiennej poprzez prefiks z \ (\${name}).
  • Zachowaj znaki specjalne. w danych wejściowych, w szczególności " i \.
  • Zezwalaj na wprowadzanie przez argumenty lub przez stdin.

Funkcja expandVars():

expandVars() {
  local txtToEval=$* txtToEvalEscaped
  # If no arguments were passed, process stdin input.
  (( $# == 0 )) && IFS= read -r -d '' txtToEval
  # Disable command substitutions and arithmetic expansions to prevent execution
  # of arbitrary commands.
  # Note that selectively allowing $((...)) or $[...] to enable arithmetic
  # expressions is NOT safe, because command substitutions could be embedded in them.
  # If you fully trust or control the input, you can remove the `tr` calls below
  IFS= read -r -d '' txtToEvalEscaped < <(printf %s "$txtToEval" | tr '`([' '\1\2\3')
  # Pass the string to `eval`, escaping embedded double quotes first.
  # `printf %s` ensures that the string is printed without interpretation
  # (after processing by by bash).
  # The `tr` command reconverts the previously escaped chars. back to their
  # literal original.
  eval printf %s "\"${txtToEvalEscaped//\"/\\\"}\"" | tr '\1\2\3' '`(['
}

Przykłady:

$ expandVars '\$HOME="$HOME"; `date` and $(ls)'
$HOME="/home/jdoe"; `date` and $(ls)  # only $HOME was expanded

$ printf '\$SHELL=${SHELL}, but "$(( 1 \ 2 ))" will not expand' | expandVars
$SHELL=/bin/bash, but "$(( 1 \ 2 ))" will not expand # only ${SHELL} was expanded
  • ze względu na wydajność, funkcja odczytuje wszystkie wejścia stdin naraz do pamięci, ale łatwo jest dostosować funkcję do podejścia linia po linii.
  • obsługuje również niestandardowe rozszerzenia zmiennych, takie jak ${HOME:0:10}, o ile nie zawierają wbudowanych poleceń lub podstawień arytmetycznych, takich jak ${HOME:0:$(echo 10)}
    • takie wbudowane podstawienia faktycznie łamią funkcję (ponieważ wszystkie $( i ` instancje są ślepo uciekane).
    • podobnie zniekształcone odwołania do zmiennych, takie jak ${HOME (brak zamknięcia }), przerywają funkcję.
  • ze względu na obsługę przez Basha podwójnych cytowanych łańcuchów, ukośniki są obsługiwane w następujący sposób:
    • \$name zapobiega ekspansji.
    • pojedynczy \, po którym nie następuje $ jest zachowany w stanie takim, w jakim jest.
    • jeśli chcesz reprezentować wiele sąsiadujących \ instancje, musisz podwoić them ; np.:
      • \\ -> \ - to samo co tylko \
      • \\\\ -> \\
    • wejście nie może zawierać następujących (rzadko używanych) znaków, które są używane do celów wewnętrznych: 0x1, 0x2, 0x3.
  • istnieje hipotetyczna obawa, że jeśli bash wprowadzi nową składnię rozszerzeń, ta funkcja może nie zapobiegać takim rozszerzeniom - zobacz poniżej rozwiązanie, które nie używa eval.

Jeśli szukasz bardziej restrykcyjnego rozwiązania, które tylko obsługuje ${name} rozszerzenia - tj. z obowiązkowe nawiasy klamrowe, ignorując $name odniesienia - patrz ta odpowiedź mojej.


Oto ulepszona wersja bash-only, eval-FREE solution from the accepted answer:

Ulepszenia to:

  • wsparcie dla rozszerzenia zarówno ${name} jak i $name odwołania do zmiennych.
  • wsparcie dla \-uciekających odniesień do zmiennych, które nie powinny być rozszerzane.
  • W przeciwieństwie do powyższego rozwiązania eval,
    • Nie-podstawowe rozszerzenia są ignorowane
    • odniesienia do zmiennych zniekształconych są ignorowane (nie łamią skryptu)
 IFS= read -d '' -r lines # read all input from stdin at once
 end_offset=${#lines}
 while [[ "${lines:0:end_offset}" =~ (.*)\$(\{([a-zA-Z_][a-zA-Z_0-9]*)\}|([a-zA-Z_][a-zA-Z_0-9]*))(.*) ]] ; do
      pre=${BASH_REMATCH[1]} # everything before the var. reference
      post=${BASH_REMATCH[5]}${lines:end_offset} # everything after
      # extract the var. name; it's in the 3rd capture group, if the name is enclosed in {...}, and the 4th otherwise
      [[ -n ${BASH_REMATCH[3]} ]] && varName=${BASH_REMATCH[3]} || varName=${BASH_REMATCH[4]}
      # Is the var ref. escaped, i.e., prefixed with an odd number of backslashes?
      if [[ $pre =~ \\+$ ]] && (( ${#BASH_REMATCH} % 2 )); then
           : # no change to $lines, leave escaped var. ref. untouched
      else # replace the variable reference with the variable's value using indirect expansion
           lines=${pre}${!varName}${post}
      fi
      end_offset=${#pre}
 done
 printf %s "$lines"
 4
Author: mklement0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:29

Ta strona opisuje odpowiedź z awk

awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < input.txt > output.txt
 3
Author: Matt Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-06 19:39:52

Idealny futerał na shtpl . (mój projekt, więc nie jest szeroko stosowany i brakuje w dokumentacji. Ale oto rozwiązanie, które oferuje w każdym razie. Może chcesz to przetestować.)

Po prostu wykonaj:

$ i=1 word=dog sh -c "$( shtpl template.txt )"

Wynik to:

the number is 1
the word is dog
Baw się dobrze.
 3
Author: zstegi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-03 17:24:14

Oto kolejne rozwiązanie pure bash:

  • używa heredoc, więc:
    • złożoność nie wzrasta ze względu na dodatkową wymaganą składnię
    • szablon może zawierać kod bash
      • to również pozwala poprawnie wciąć rzeczy. Patrz poniżej.
  • nie używa evalu, więc:
    • brak problemów z renderowaniem końcowych pustych linii
    • brak problemów z cytatami w szablon

$ cat code

#!/bin/bash
LISTING=$( ls )

cat_template() {
  echo "cat << EOT"
  cat "$1"
  echo EOT
}

cat_template template | LISTING="$LISTING" bash

$ cat template (z końcowymi znakami nowej linii i podwójnymi cudzysłowami)

<html>
  <head>
  </head>
  <body> 
    <p>"directory listing"
      <pre>
$( echo "$LISTING" | sed 's/^/        /' )
      <pre>
    </p>
  </body>
</html>

Wyjście

<html>
  <head>
  </head>
  <body> 
    <p>"directory listing"
      <pre>
        code
        template
      <pre>
    </p>
  </body>
</html>
 3
Author: Tomáš Pospíšek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-18 11:52:16

Oto inne rozwiązanie: wygenerować skrypt bash ze wszystkimi zmiennymi i zawartością pliku szablonu, skrypt ten wyglądałby tak:

word=dog           
i=1                
cat << EOF         
the number is ${i} 
the word is ${word}

EOF                

Jeśli dodamy ten skrypt do Basha, wygenerujemy żądane wyjście:

the number is 1
the word is dog

Oto jak wygenerować ten skrypt i wprowadzić go do Basha:

(
    # Variables
    echo word=dog
    echo i=1

    # add the template
    echo "cat << EOF"
    cat template.txt
    echo EOF
) | bash

Dyskusja

  • nawiasy otwierają sub powłokę, jej celem jest zgrupowanie wszystkich wygenerowanych wyników
  • wewnątrz sub shell, generujemy wszystkie deklaracje zmiennych
  • również w powłoce sub generujemy polecenie cat z HEREDOC
  • wreszcie, karmimy wyjście sub shell do bash i produkować żądane wyjście
  • Jeśli chcesz przekierować to wyjście do pliku, zastąp ostatnią linię przez:

    ) | bash > output.txt
    
 2
Author: Hai Vu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-04 15:00:02

Możesz również użyć bashible (który wewnętrznie wykorzystuje podejście oceniające opisane powyżej/poniżej).

Jest przykład, jak wygenerować HTML z wielu części:

Https://github.com/mig1984/bashible/tree/master/examples/templates

 1
Author: Jan Molič,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-03 13:30:47
# Usage: template your_file.conf.template > your_file.conf
template() {
        local IFS line
        while IFS=$'\n\r' read -r line ; do
                line=${line//\\/\\\\}         # escape backslashes
                line=${line//\"/\\\"}         # escape "
                line=${line//\`/\\\`}         # escape `
                line=${line//\$/\\\$}         # escape $
                line=${line//\\\${/\${}       # de-escape ${         - allows variable substitution: ${var} ${var:-default_value} etc
                # to allow arithmetic expansion or command substitution uncomment one of following lines:
#               line=${line//\\\$\(/\$\(}     # de-escape $( and $(( - allows $(( 1 + 2 )) or $( command ) - UNSECURE
#               line=${line//\\\$\(\(/\$\(\(} # de-escape $((        - allows $(( 1 + 2 ))
                eval "echo \"${line}\"";
        done < "$1"
}

Jest to czysta funkcja bash dostosowana do Twoich upodobań, używana w produkcji i nie powinna pękać na żadnym wejściu. Jeśli się zepsuje - daj mi znać.

 1
Author: ttt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-12 18:50:21

Oto funkcja bash, która zachowuje białe znaki:

# Render a file in bash, i.e. expand environment variables. Preserves whitespace.
function render_file () {
    while IFS='' read line; do
        eval echo \""${line}"\"
    done < "${1}"
}
 0
Author: Igor Katson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-01 03:27:00

Oto zmodyfikowany skrypt perl oparty na kilku innych odpowiedziach:

perl -pe 's/([^\\]|^)\$\{([a-zA-Z_][a-zA-Z_0-9]*)\}/$1.$ENV{$2}/eg' -i template

Funkcje (w oparciu o moje potrzeby, ale powinny być łatwe do modyfikacji):

  • pomija rozszerzenia parametrów ucieczki (np. \${VAR}).
  • Obsługuje rozszerzenia parametrów postaci ${VAR}, ale nie $VAR.
  • zastępuje ${VAR} pustym łańcuchem, jeśli nie ma VAR envar.
  • obsługuje tylko a-z, A-Z, 0-9 i znaki podkreślenia w nazwie (z wyłączeniem cyfr na pierwszej pozycji).
 0
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-22 02:02:54

Zamiast wymyślać koło idź z envsubst Może być stosowany w prawie każdym scenariuszu, na przykład do budowania plików konfiguracyjnych ze zmiennych środowiskowych w kontenerach docker.

Jeśli na Macu upewnij się, że masz homebrew to podlinkuj go z gettext:

brew install gettext
brew link --force gettext

./ szabloncfg

# We put env variables into placeholders here
this_variable_1 = ${SOME_VARIABLE_1}
this_variable_2 = ${SOME_VARIABLE_2}

./.env:

SOME_VARIABLE_1=value_1
SOME_VARIABLE_2=value_2

./configure.sh

#!/bin/bash
cat template.cfg | envsubst > whatever.cfg

Teraz wystarczy użyć:

# make script executable
chmod +x ./configure.sh
# source your variables
. .env
# export your variables
# In practice you may not have to manually export variables 
# if your solution dependins on tools that utilise .env file 
# automatically like pipenv etc. 
export SOME_VARIABLE_1 SOME_VARIABLE_2
# Create your config file
./configure.sh
 0
Author: smentek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-31 08:45:07