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?


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.


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

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


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"

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)


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

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"

-1

Użyj tego zamiast tego

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

to działa dla mnie po prostu usuń cytaty


-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"

6
Czy to różni się od odpowiedzi Dave'a ?
devnull
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.