Zastąp ciąg w skrypcie powłoki za pomocą zmiennej

94

Używam poniższego kodu do zamiany ciągu znaków w skrypcie powłoki.

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

ale jest zastępowany przez $replacezamiast wartości tej zmiennej.

Czy ktokolwiek mógłby powiedzieć, co poszło nie tak?

Vijay
źródło
Często zadawane pytania dotyczące obsługi wartości zawierających ukośniki można znaleźć na stronie stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee

Odpowiedzi:

147

Jeśli chcesz interpretować $replace, nie powinieneś używać apostrofów, ponieważ uniemożliwiają one podstawianie zmiennych.

Próbować:

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

zakładając, że chcesz wstawić cudzysłowy. Jeśli nie chcesz cytatów, użyj:

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

Transkrypcja:

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

Uważaj tylko, aby upewnić się, że ${replace}nie ma żadnych znaczących postaci sed(jak /na przykład), ponieważ spowoduje to zamieszanie, chyba że ucieknie. Ale jeśli, jak mówisz, zamieniasz jedną liczbę na inną, nie powinno to stanowić problemu.

paxdiablo
źródło
nie chcę wstawiać cudzysłowów. chcę, aby jeden numer został zastąpiony innym
Vijay
1
paxdiablo: setrównież nie jest konieczne (a jak zamierzałeś go wykorzystać?). Po prostu replace=987654321.
Roman Cheplyaka,
Zwykle zawsze używam, exportaby upewnić się, że zmienne są ustawione dla dzieci, ale, jak mówisz, równie łatwo możesz tego uniknąć. Jednak użycie lub nie exportjest tutaj nieistotne (kwestia stylu) i nie ma wpływu na rzeczywistą odpowiedź, czyli sposób użycia zmiennych w sedpoleceniu.
paxdiablo
Wydaje się, że to rozwiązanie nie działa z -iopcją. Wiedziałbyś dlaczego? lub jak to działa?
Gabriel,
1
Może również zwrócić uwagę, że przejście z pojedynczych cudzysłowów do podwójnych cudzysłowów wymaga, aby jakikolwiek znak $lub `w sedskrypcie był poprzedzony odwrotnym ukośnikiem, aby chronić go przed mechanizmem zastępowania przez powłokę ciągów w podwójnych cudzysłowach.
tripleee
74

możesz użyć powłoki (bash / ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc
ghostdog74
źródło
3
Może chciałbym wspomnieć, że jest to specyficzne dla basha (i ksh?). Prawdopodobnie nie jest to ważne dla większości ludzi, ale niektórzy z nas są nadal zmuszeni do pracy na starożytnym UNIXenie :-)
paxdiablo
6
Uważaj, to również nie działa na desce rozdzielczej, która występuje /bin/shw wielu nowoczesnych Linuksach.
phihag
28

Nie jest to specyficzne dla pytania, ale dla osób, które potrzebują tego samego rodzaju funkcjonalności rozszerzonej dla jasności z poprzednich odpowiedzi:

# 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
pion
źródło
8

Pojedyncze cudzysłowy są bardzo mocne. Po wejściu do środka nic nie możesz zrobić, aby wywołać podstawianie zmiennych, dopóki nie wyjdziesz. Zamiast tego użyj cudzysłowów:

echo $LINE | sed -e "s/12345678/$replace/g"
Dave
źródło
4
echo $LINE | sed -e 's/12345678/'$replace'/g'

nadal możesz używać pojedynczych cudzysłowów, ale musisz je „otworzyć”, jeśli chcesz, aby zmienna została rozwinięta we właściwym miejscu. w przeciwnym razie ciąg jest traktowany „dosłownie” (jak poprawnie stwierdził @paxdiablo, jego odpowiedź jest również poprawna)

akira
źródło
Wiąże się to z tym, że użycie $replaceznaków poza cudzysłowami spowoduje, że powłoka wykona tokenizację białych znaków i rozwinięcie wartości z użyciem symboli wieloznacznych. Wydaje się, że działa to z prostymi wartościami, ale może dramatycznie wybuchnąć w przypadku nietrywialnych łańcuchów. Nie używaj tego w kodzie produkcyjnym.
tripleee
2

Aby pozwolić powłoce rozwinąć zmienną, musisz użyć podwójnych cudzysłowów, takich jak

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

Spowoduje to uszkodzenie, jeśli $replacezawiera sedznaki specjalne ( #, \). Możesz jednak wstępnie $replaceje zacytować:

replace_quoted=$(printf '%s' "$replace" | sed 's/[#\]/\\\0/g')
sed -i "s#12345678#$replace_quoted#g" file.txt
Matthieu Moy
źródło
0

Miałem podobny wymóg do tego, ale mój zamiennik var zawierał znak ampersand. Ucieczka przed ampersandem rozwiązała mój problem:

replace="salt & pepper"
echo "pass the salt" | sed "s/salt/${replace/&/\&}/g"
Richard Salt
źródło
-1

Użyj tego zamiast tego

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

to działa dla mnie po prostu usuń cytaty

Tunde Pizzle
źródło
-2

Wolę używać podwójnych cudzysłowów, ponieważ pojedyncze znaki są bardzo potężne, ponieważ ich używaliśmy, jeśli nie jesteśmy w stanie niczego zmienić w środku lub możemy wywołać zmienne podstawienie.

więc używaj zamiast tego podwójnych cudzysłowów.

echo $LINE | sed -e "s/12345678/$replace/g"
SteveScm
źródło
6
Czy to różni się od odpowiedzi Dave'a ?
devnull