Mam kilka plików tekstowych, w których wprowadziłem zmienne powłoki (na przykład $ VAR1 lub $ VAR2).
Chciałbym wziąć te pliki (jeden po drugim) i zapisać je w nowych plikach, gdzie wszystkie zmienne zostałyby zastąpione.
Aby to zrobić, użyłem następującego skryptu powłoki (znalezionego w StackOverflow):
while read line
do
eval echo "$line" >> destination.txt
done < "source.txt"
Działa to bardzo dobrze w przypadku bardzo podstawowych plików.
Jednak w przypadku bardziej złożonych plików polecenie „eval” robi za dużo:
Wiersze zaczynające się od „#” są pomijane
Analiza plików XML skutkuje mnóstwem błędów
Czy jest lepszy sposób, aby to zrobić? (w skrypcie powłoki ... wiem, że można to łatwo zrobić na przykład za pomocą Anta)
Z poważaniem
envsubst
jest częścią GNU gettextsource.txt
zawiera jakiekolwiek$
znaki spoza rozwijania zmiennych,envsubst
również je zamieni i nie ma sposobu na uniknięcie$
. Typowe (brzydkie) obejście toexport DOLLAR="$"
.W odniesieniu do odpowiedzi 2, omawiając envsubst, zapytałeś:
Odpowiedź brzmi: po prostu musisz wyeksportować swoje zmienne przed wywołaniem
envsubst
.Możesz również ograniczyć ciągi zmiennych, które chcesz zamienić w danych wejściowych, używając
envsubst
SHELL_FORMAT
argumentu (unikając niezamierzonego zastąpienia łańcucha w wejściu wspólną wartością zmiennej powłoki - np$HOME
.).Na przykład:
export VAR1='somevalue' VAR2='someothervalue' MYVARS='$VAR1:$VAR2' envsubst "$MYVARS" <source.txt >destination.txt
Zastąpi wszystkie wystąpienia
$VAR1
i$VAR2
(i tylkoVAR1
aVAR2
) wsource.txt
z'somevalue'
i'someothervalue'
odpowiednio.źródło
'
które są używane do ustawiania,MYVARS
są kluczoweexport
,envsubst
lub jakiekolwiek polecenie przeplotu może się nie powieść, gdy tekst do zastąpienia jest duży. Odniesienie.SHELL_FORMAT
argumentu (tj."$MYVARS"
) powoduje zastąpienie wszystkich eksportowanych zmiennych. Jeśli tego potrzebujesz, nie martw się.Wiem, że ten temat jest stary, ale mam prostsze działające rozwiązanie bez eksportu zmiennych. Może być onelinerem, ale ja wolę rozdzielać
\
na końcu linii.var1='myVar1'\ var2=2\ var3=${var1}\ envsubst '$var1,$var3' < "source.txt" > "destination.txt" # ^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^ # define which to replace input output
Zmienne muszą być zdefiniowane w tej samej linii, w jakiej
envsubst
mają być traktowane jako zmienne środowiskowe.'$var1,$var3'
Jest opcjonalny tylko wymienić te wyszczególnione. Wyobraź sobie plik wejściowy zawierający,${VARIABLE_USED_BY_JENKINS}
którego nie należy zastępować.źródło
$ export MY_ENV_VAR=congratulation
$MY_ENV_VAR
Możesz także użyć wszystkich innych zmiennych ENV zdefiniowanych przez Twój system, takich jak (w systemie Linux) $ TERM, $ SHELL, $ HOME ...
$ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" < in.txt > out.txt
i powinieneś zobaczyć „gratulacje”.
źródło
Jeśli naprawdę chcesz używać tylko basha (i seda), przejdę przez każdą z twoich zmiennych środowiskowych (zwróconych
set
w trybie posix) i zbuduję z tego kilka-e 'regex'
dla seda, zakończonych przez-e 's/\$[a-zA-Z_][a-zA-Z0-9_]*//g'
, a następnie przekażę to wszystko do sed.Perl wykonałby jednak lepszą robotę, masz dostęp do zmiennych środowiskowych jako tablicę i możesz wykonywać zastępcze pliki wykonywalne, więc każdą zmienną środowiskową dopasowujesz tylko raz.
źródło
perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' "$main_tf_file"
Właściwie musisz zmienić
read
na,read -r
który spowoduje, że będzie ignorował odwrotne ukośniki.Powinieneś także unikać cytatów i odwrotnych ukośników. Więc
while read -r line; do line="${line//\\/\\\\}" line="${line//\"/\\\"}" line="${line//\`/\\\`}" eval echo "\"$line\"" done > destination.txt < source.txt
Wciąż jednak straszny sposób na ekspansję.
źródło
Wyeksportuj wszystkie potrzebne zmienne, a następnie użyj onlinera perla
TEXT=$(echo "$TEXT"|perl -wpne 's#\${?(\w+)}?# $ENV{$1} // $& #ge;')
Spowoduje to zastąpienie wszystkich zmiennych ENV obecnych w TEKST wartościami rzeczywistymi. Cytaty również są zachowane :)
źródło
Jeśli chcesz, aby zmienne env zostały zastąpione w plikach źródłowych, zachowując wszystkie zmienne inne niż env bez zmian, możesz użyć następującego polecenia:
envsubst "$(printf '${%s} ' $(env | sed 's/=.*//'))" < source.txt > destination.txt
W tym miejscu wyjaśniono składnię zastępowania tylko określonych zmiennych . Powyższe polecenie używa podpowłoki do wyświetlenia wszystkich zdefiniowanych zmiennych, a następnie przekazuje je do
envsubst
Więc jeśli istnieje zdefiniowana zmienna env o nazwie
$NAME
, a Twójsource.txt
plik wygląda następująco:Hello $NAME Your balance is 123 ($USD)
destination.txt
Będą:Hello Arik Your balance is 123 ($USD)
Zauważ, że
$NAME
został zastąpiony i$USD
pozostawiony nietkniętyźródło
Wywołaj plik binarny Perla, w trybie wyszukiwania i zamiany na wiersz (the
-pi
), uruchamiając kod Perla (the-e
) w pojedynczych cudzysłowach, który iteruje po kluczach specjalnego%ENV
skrótu zawierającego wyeksportowane nazwy zmiennych jako klucze i wyeksportowane wartości zmiennych jako wartości kluczy i dla każdej iteracji po prostu zamień ciąg zawierający a na$<<key>>
jego<<value>>
.perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' file
Uwaga: dodatkowa obsługa logiki jest wymagana w przypadkach, w których dwie lub więcej zmiennych zaczyna się od tego samego ciągu ...
źródło
envsubst
wygląda na coś, czego chciałem użyć, ale-v
opcja trochę mnie zaskoczyła.Chociaż
envsubst < template.txt
działał dobrze, to samo z opcją-v
nie działało:Jak pisałem, to nie działało:
Musiałem to zrobić, aby działało:
Może to komuś pomoże.
źródło