Odpowiedzi:
Użyj alternatywnego separatora wyrażeń regularnych, co sed
pozwala na użycie dowolnego separatora (w tym znaków kontrolnych ):
sed "s~$var~replace~g" $file
$var
Czysta odpowiedź basha: użyj interpretacji parametrów, aby odwrócić ukośnik - uciec przed wszystkimi ukośnikami w zmiennej:
var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file
${parameter/pattern/string}
. W tym przypadku parametr to var
, wzorzec to /\/
, a ciąg to \\/
. Wszystkie wystąpienia wzorca są zastępowane, ponieważ wzór zaczyna się od /
.
Użycie /
w sedzie jako separatora spowoduje konflikt z ukośnikami w zmiennej podczas podstawiania, w wyniku czego pojawi się błąd. Jednym ze sposobów obejścia tego jest użycie innego ogranicznika, który jest unikalny dla wszystkich znaków znajdujących się w tej zmiennej.
var="/Users/Documents/name/file"
możesz użyć znaku octothorpe, który pasuje do okazji (lub dowolnego innego znaku, który nie jest /
łatwy w użyciu)
sed "s#$var#replace#g"
lub
sed 's#$'$var'#replace#g'
jest to odpowiednie, gdy zmienna nie zawiera spacji
lub
sed 's#$"'$var'"#replace#g'
Rozsądniej jest skorzystać z powyższego, ponieważ jesteśmy zainteresowani zastąpieniem tego, co jest w tej zmiennej, tylko w porównaniu z podwójnym cudzysłowem całego polecenia, co może spowodować, że powłoka interpetuje dowolny znak, który może być uznany za specjalny znak powłoki.
$var
zawiera ~
, oczywiście będziesz musiał wybrać inny separator. Błąd „niezakończony” brzmi tak, jakby twój $var
zawierał nową linię; możesz to naprawić, usuwając odwrotnym ukośnikiem każdą nową linię w wartości, ale nie sądzę, że jest to całkowicie przenośne. W zasadzie nie ma to związku z problemem cięć wartości.
sed -i "s~blah~$var~g" file
z cudzysłowami tylko wokół właściwego sed
skryptu.
To stare pytanie, ale żadna z odpowiedzi nie omawia operacji poza s/from/to/
bardzo szczegółowymi informacjami.
Ogólna forma sed
oświadczenia to
*address* *action*
gdzie adres może być zakresem wyrażenia regularnego lub zakresem numerów wierszy (lub pustym, w którym to przypadku akcja jest stosowana do każdego wiersza wejściowego). Na przykład
sed '1,4d' file
usunie linie od 1 do 4 ( adres to zakres numerów linii, 1,4
a czynnością jest d
polecenie usunięcia); i
sed '/ick/,$s/foo/bar/' file
zastąpi pierwsze wystąpienie foo
ze bar
na każdej linii pomiędzy pierwszym meczu na regex ick
i końca pliku (the adres jest zasięg /ick/,$
i działanie jest s
komenda substytutems/foo/bar/
).
W tym kontekście, jeśli ick
pochodzi ze zmiennej, możesz to zrobić
sed "/$variable/,\$s/foo/bar/"
(zwróć uwagę na użycie podwójnych cudzysłowów zamiast pojedynczych, aby powłoka mogła interpolować zmienną i konieczność cytowania dosłownego znaku dolara wewnątrz podwójnych cudzysłowów), ale jeśli zmienna zawiera ukośnik, pojawi się błąd składniowy. (Powłoka rozwija zmienną, a następnie przekazuje wynikowy ciąg do sed
; więc sed
widzi tylko tekst dosłowny - nie ma pojęcia o zmiennych powłoki).
Lekarstwem jest użycie innego separatora (gdzie oczywiście musisz mieć możliwość użycia znaku, który nie może występować w wartości zmiennej), ale w przeciwieństwie do s%foo%bar%
przypadku, potrzebujesz również ukośnika odwrotnego przed separatorem, jeśli chcesz użyć innego separator niż domyślny /
:
sed "\\%$variable%,\$s/foo/bar/" file
(w pojedynczych cudzysłowach wystarczyłby oczywiście pojedynczy lewy ukośnik); lub możesz osobno zmienić znaczenie każdego ukośnika w wartości. Ta konkretna składnia to tylko Bash:
sed "/${variable//\//\\/}/,\$s/foo/bar/" file
lub jeśli używasz innej powłoki, spróbuj
escaped=$(echo "$variable" | sed 's%/%\\/%g')
sed "s/$escaped/,\$s/foo/bar/" file
Dla jasności, gdyby $variable
zawierał łańcuch, 1/2
powyższe polecenia byłyby równoważne
sed '\%1/2%,$s/foo/bar/' file
w pierwszym przypadku i
sed '/1\/2/,$s/foo/bar/' file
w sekundę.
Użyj Perla, gdzie zmienne są obywatelami pierwszej klasy, a nie tylko rozwijaniem makr:
var=/Users/Documents/name/file perl -pe 's/\Q$ENV{var}/replace/g' $file
-p
czyta dane wejściowe wiersz po wierszu i drukuje wiersz po przetworzeniu\Q
cytuje wszystkie metaznaki w następującym ciągu (nie są potrzebne dla wartości tutaj prezentowanej, ale konieczne, jeśli wartość zawierała [
lub inne wartości specjalne dla regularnych wyrażeń)