Sostituisci una stringa nello script della shell utilizzando una variabile


93

Sto usando il codice seguente per sostituire una stringa all'interno di uno script di shell.

echo $LINE | sed -e 's/12345678/"$replace"/g'

ma viene sostituito con $replaceinvece del valore di quella variabile.

Qualcuno potrebbe dire cosa è andato storto?


Per la questione relativa comune circa la gestione dei valori con i tagli in loro, vedere stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee

Risposte:


146

Se vuoi interpretare $replace, non dovresti usare virgolette singole poiché impediscono la sostituzione delle variabili.

Provare:

echo $LINE | sed -e "s/12345678/\"${replace}\"/g"

supponendo che tu voglia inserire le virgolette. Se non vuoi le virgolette, usa:

echo $LINE | sed -e "s/12345678/${replace}/g"

Trascrizione:

pax> export replace=987654321
pax> echo X123456789X | sed "s/123456789/${replace}/"
X987654321X
pax> _

Fai solo attenzione a assicurarti che ${replace}non abbia caratteri significativi sed(come /ad esempio) poiché causerà confusione a meno che non venga evitato. Ma se, come dici, stai sostituendo un numero con un altro, non dovrebbe essere un problema.


Non voglio che le virgolette vengano inserite. Voglio che un numero venga sostituito con un altro
Vijay

1
paxdiablo: setinoltre non è necessario (e come lo useresti comunque?). Solo replace=987654321.
Roman Cheplyaka

Di solito lo uso sempre exportper assicurarmi che le variabili siano impostate per i bambini ma, come dici tu, potresti evitarlo altrettanto facilmente. Tuttavia, l'uso o meno di exportè irrilevante qui (un problema di stile) e non ha alcun effetto sulla risposta effettiva, che è come utilizzare le variabili all'interno di un sedcomando.
paxdiablo

Questa soluzione non sembra funzionare con l' -iopzione. Sapresti perché? o come farlo funzionare?
Gabriel

1
Forse anche sottolineare che il passaggio da virgolette singole a doppie richiede che qualsiasi $o `nello sedscript sia sottoposto a escape con un backslash, per proteggerlo dal meccanismo di sostituzione della shell per le stringhe con virgolette doppie.
tripleee

73

puoi usare la shell (bash / ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc

3
Potrei menzionare che è specifico di bash (e ksh?). Probabilmente non è importante per la maggior parte delle persone, ma alcuni di noi sono ancora costretti a lavorare su UNIXen antico :-)
paxdiablo

6
Attenzione, anche questo fallisce sul trattino, che è /bin/sh su molti Linux moderni.
phihag

26

Non specifico per la domanda, ma per le persone che necessitano dello stesso tipo di funzionalità ampliato per chiarezza dalle risposte precedenti:

# create some variables
str="someFileName.foo"
find=".foo"
replace=".bar"
# notice the the str isn't prefixed with $
#    this is just how this feature works :/
result=${str//$find/$replace}
echo $result    
# result is: someFileName.bar

str="someFileName.sally"
find=".foo"
replace=".bar"
result=${str//$find/$replace}
echo $result    
# result is: someFileName.sally because ".foo" was not found

8

Le virgolette singole sono molto forti. Una volta dentro, non puoi fare nulla per invocare la sostituzione delle variabili, finché non esci. Usa invece le virgolette doppie:

echo $LINE | sed -e "s/12345678/$replace/g"


4
echo $LINE | sed -e 's/12345678/'$replace'/g'

puoi ancora utilizzare virgolette singole, ma devi "aprirle" quando vuoi che la variabile si espanda al posto giusto. altrimenti la stringa viene presa "letteralmente" (come ha affermato correttamente @paxdiablo, anche la sua risposta è corretta)


Questo ha il problema che l'utilizzo $replaceal di fuori delle virgolette farà sì che la shell esegua la tokenizzazione degli spazi bianchi e l'espansione dei caratteri jolly sul valore. Questo sembrerà funzionare con valori semplici, ma potrebbe esplodere in modo drammatico su stringhe non banali. Non utilizzarlo nel codice di produzione.
tripleee

2

Per consentire alla shell di espandere la variabile, è necessario utilizzare virgolette doppie come

sed -i "s#12345678#$replace#g" file.txt

Questo si interromperà se $replacecontiene sedcaratteri speciali ( #, \). Ma puoi pre $replace- elaborarli per citarli:

replace_quoted=$(printf '%s' "$replace" | sed 's/[#\]/\\\0/g')
sed -i "s#12345678#$replace_quoted#g" file.txt

0

Avevo un requisito simile a questo, ma la mia variabile sostitutiva conteneva una e commerciale. Fuggire dalla e commerciale in questo modo ha risolto il mio problema:

replace="salt & pepper"
echo "pass the salt" | sed "s/salt/${replace/&/\&}/g"

-1

Usa questo invece

echo $LINE | sed -e 's/12345678/$replace/g'

questo funziona per me basta semplicemente rimuovere le virgolette


-2

Preferisco usare le virgolette doppie, poiché i singoli qupt sono molto potenti in quanto li abbiamo usati se non siamo in grado di cambiare nulla al loro interno o possiamo invocare la sostituzione della variabile.

quindi usa le virgolette doppie instaed.

echo $LINE | sed -e "s/12345678/$replace/g"

6
È diverso dalla risposta di Dave ?
devnull
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.