2013-01-04 4 views
36

Ho diversi file di testo in cui ho introdotto variabili di shell ($ VAR1 o $ VAR2 per esempio).Come sostituire le variabili di shell in file di testo complessi

Vorrei prendere quei file (uno per uno) e salvarli in nuovi file in cui tutte le variabili sarebbero state sostituite.

Per fare questo, ho usato il seguente script di shell (trovato su StackOverflow):

while read line 
do 
    eval echo "$line" >> destination.txt 
done < "source.txt" 

Questo funziona molto bene sui file di base.

Ma sui file più complessi, il comando "eval" non troppo:

  • linee che iniziano con "#" sono saltati

  • file XML parsing risultati in tonnellate di errori

C'è un modo migliore per farlo? (In script di shell ... So che questo è fatto facilmente con Ant per esempio)

Cordiali saluti

risposta

88

Guardando, si scopre sul mio sistema che esiste un comando envsubst che fa parte del pacchetto gettext-base.

Quindi, questo lo rende facile:

envsubst < "source.txt" > "destination.txt" 
+2

Grande! Ma funziona solo per le variabili di ambiente. Come posso farlo funzionare con le variabili dichiarate nel mio script .sh? – Ben

+5

@Ben: usa 'export' (prima di chiamare envsubst) per ogni variabile che vuoi usare in envsubst – tlo

+4

'envsubst' è parte di [GNU gettext] (https://www.gnu.org/software/gettext/manual/ html_node/envsubst-Invocation.html) – Andy

0

Se davvero solo vuole usare bash (e sed), quindi vorrei passare attraverso ogni dell'ambiente variabili (come restituito da set in modalità posix) e costruire un gruppo di -e 'regex' per sed da quello, terminato da un -e 's/\$[a-zA-Z_][a-zA-Z0-9_]*//g', quindi passare tutto ciò a sed.

Perl farebbe comunque un lavoro più bello, si ha accesso alle vars di ambiente come una matrice e si possono fare sostituzioni eseguibili in modo da far corrispondere una variabile di ambiente una sola volta.

0

In realtà è necessario modificare il read in read -r che farà ignorare i backslash.

Inoltre, è necessario evitare le virgolette e i backslash. Così

while read -r line; do 
    line="${line//\\/\\\\}" 
    line="${line//\"/\\\"}" 
    line="${line//\`/\\\`}" 
    eval echo "\"$line\"" 
done > destination.txt < source.txt 

Ancora un modo terribile per fare l'espansione però.

+5

Non dimenticare '$ (rm -Rf /)' pure ... – derobert

+0

Infatti, questo è il rischio quando si esegue "eval" su un file che potrebbe contenere codice errato – Ben

34

In riferimento alla risposta 2, quando si parla di envsubst, lei ha chiesto: "Come posso farlo funzionare con le variabili che vengono dichiarate nel mio script .sh?"

La risposta è che è semplicemente necessario esportare le variabili prima di chiamare envsubst.

È inoltre possibile limitare le stringhe variabili che si desidera sostituire nell'input utilizzando l'argomento envsubst SHELL_FORMAT (evitando la sostituzione involontaria di una stringa nell'input con un valore di variabile shell comune, ad esempio $ HOME).

Per esempio:

export VAR1='somevalue' VAR2='someothervalue' 
MYVARS='$VAR1:$VAR2' 

envsubst "$MYVARS" <source.txt >destination.txt 

sostituirà tutte le istanze di $ VAR1 e VAR2 $ (e solo VAR1 e VAR2) in source.txt con 'somevalue' e 'someothervalue' rispettivamente.

+4

Le virgolette singole '' 'utilizzate per impostare' MYVARS' sono cruciali –

+0

L'omissione di "$ MYVARS" dal comando "envsubst" funziona anche. – ram

+0

Si noti che 'export',' envsubst' o qualsiasi comando di interleaving possono fallire quando il testo da sostituire è grande. [Riferimento.] (Https://stackoverflow.com/a/28865503/2908724) – bishop

0

envsubst sembra esattamente come qualcosa che volevo usare, ma l'opzione -v mi ha sorpreso un po '.

Mentre envsubst < template.txt stava funzionando benissimo, lo stesso con l'opzione -v non funzionava:

$ cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 7.1 (Maipo) 
$ envsubst -V 
envsubst (GNU gettext-runtime) 0.18.2 
Copyright (C) 2003-2007 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. 
Written by Bruno Haible. 

Come ho scritto, questo non funzionava:

$ envsubst -v < template.txt 
envsubst: missing arguments 
$ cat template.txt | envsubst -v 
envsubst: missing arguments 

ho dovuto fare questo per renderlo lavoro:

TEXT=`cat template.txt`; envsubst -v "$TEXT" 

Forse aiuta qualcuno.

0

Esporta tutti i varaibles necessari e quindi utilizzare un Perl onliner

TEXT=$(echo "$TEXT"|perl -wpne 's#\${?(\w+)}?# $ENV{$1} // $& #ge;')

Questo sostituirà tutte le variabili ENV presenti nel testo con valori reali. Le quotazioni sono anche conservati :)

1
  1. Definire la
$ export MY_ENV_VAR=congratulation 
  1. Crea file modello variabile ENV (in.txt) con i seguenti contenuti
$MY_ENV_VAR 

È inoltre possibile utilizzare tutte le altre variabili ENV definito dal vostro sistema come (in linux) $ TERM, $ SHELL, $ HOME ...

  1. Esegui questo comando per raplace tutti ENV-variabili nel file in.txt e di scrivere il risultato out.txt
$ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" <in.txt> out.txt 
  1. controllare il contenuto dei file di out.txt
$ cat out.txt 

e dovresti vedere "congratulazioni".

2

So che questo argomento è obsoleto, ma ho una soluzione di lavoro più semplice senza esportare le variabili. Può essere un oneliner, ma preferisco dividere usando \ alla fine della linea.

var1='myVar1'\ 
var2=2\ 
var3=${var1}\ 
envsubst '$var1,$var3' < "source.txt" > "destination.txt" 

#   ^^^^^^^^^^^ ^^^^^^^^^^  ^^^^^^^^^^^^^^^ 
# define which to replace input   output 

Le variabili devono essere definiti alla stessa linea envsubst è quello di ottenere considerato come variabili d'ambiente.

Il '$var1,$var3' è opzionale per sostituire solo quelli specificati. Immagina un file di input contenente ${VARIABLE_USED_BY_JENKINS} che non dovrebbe essere sostituito.

Problemi correlati