Jeśli chcesz zastąpić słowo kluczowe ciągiem znaków za pomocą sed, sed próbuje zinterpretować ciąg zastępujący. Jeśli zastępujący ciąg znaków zawiera znaki, które sed uważa za specjalne, takie jak znak „/”, to zawiedzie, chyba że oczywiście miałeś na myśli, że zastępujący ciąg znaków ma znaki, które mówią sedowi, jak postępować.
Dawny:
VAR="hi/"
sed "s/KEYWORD/$VAR/g" somefile
Czy jest jakiś sposób, aby powiedzieć sedowi, aby nie próbował interpretować ciągu zastępującego znaki specjalne? Chcę tylko móc zastąpić słowo kluczowe w pliku zawartością zmiennej, bez względu na to, co to jest.
bash
shell-script
sed
Tal
źródło
źródło
sed
i nie być wyjątkowymi, po prostu uciec od nich ukośnikiem odwrotnym.VAR='hi\/'
nie daje takiego problemu.sed(1)
po prostu interpretuje to, co dostaje. W twoim przypadku jest to możliwe dzięki interpolacji powłoki. Uważam, że nie możesz robić tego, co chcesz, ale sprawdź instrukcję. Wiem, że w Perlu (który jest znośnymsed
zamiennikiem, ze znacznie bogatszymi wyrażeniami regularnymi) możesz określić, że ciąg ma być brany dosłownie, ponownie sprawdź instrukcję.Odpowiedzi:
Możesz używać Perla zamiast sed z
-p
(zakładaj pętlę nad wejściem) i-e
(podaj program w wierszu poleceń). Dzięki Perlowi możesz uzyskać dostęp do zmiennych środowiskowych bez interpolacji ich w powłoce. Pamiętaj, że zmienną należy wyeksportować :Jeśli nie chcesz eksportować zmiennej wszędzie, podaj ją tylko dla tego procesu:
Zauważ, że składnia wyrażeń regularnych Perla domyślnie nieco różni się od składni sed.
źródło
PATTERN
zmiennej środowiskowej , a nie argumentów. W każdym razie ten błąd byłbyE2BIG
, który dostaniesz równie dobrze, jeśli użyjeszsed
.Są tylko 4 znaki specjalne części zamiennej: \, &, znak nowej linii i separator ( ref )
źródło
s///
jest nie wyrażenie regularne, to naprawdę tylko ciąg (z wyjątkiem backslash-ucieczek i&
). Jeśli zastępujący ciąg jest tak długi, jednowarstwowa powłoka nie jest twoim rozwiązaniem.Najprostszym rozwiązaniem, które nadal poprawnie obsługiwałoby znaczną większość wartości zmiennych, byłoby użycie znaku niedrukowalnego jako separatora
sed
polecenia zastępczego.W
vi
można uciec od dowolnego znaku kontrolnego, naciskając Ctrl-V (częściej zapisywany jako^V
). Więc jeśli użyjesz jakiegoś znaku kontrolnego (często używam^A
jako ogranicznik w tych przypadkach), twojesed
polecenie zostanie złamane tylko, jeśli ten niedrukowalny znak jest obecny w zmiennej, w której upuszczasz.Więc wpisz
"s^V^AKEYWORD^V^A$VAR^V^Ag"
i co byś (wvi
) wyglądałby:Działa to tak długo, jak długo
$VAR
nie zawiera znaku niedrukowalnego^A
- co jest niezwykle mało prawdopodobne.Oczywiście, jeśli przekazujesz wartość wejściową od użytkownika
$VAR
, wszystkie zakłady są wyłączone i lepiej oczyść swoje dane wejściowe, zamiast polegać na trudnych do wpisania znakach kontrolnych dla przeciętnego użytkownika.Jednak w rzeczywistości należy uważać na więcej niż ciąg ogranicznika. Na przykład,
&
gdy występuje w ciągu zastępującym, oznacza „cały dopasowany tekst”. Np.s/stu../my&/
Zamieniłbym „stuff” na „mystuff”, „stung” na „mystung” itp. Więc jeśli możesz mieć dowolny znak w zmiennej, którą upuszczasz jako ciąg zastępczy, ale chcesz użyć literału tylko wartość zmiennej, musisz wykonać pewne operacje dezynfekcji danych, zanim będziesz mógł użyć zmiennej jako łańcucha zastępczego wsed
. (Jednak dezynfekcję danych można również wykonaćsed
.)źródło
sed
„si
dowodzenia nsert. Alesed
nie jest dobrym narzędziem do przetwarzania ogromnych ilości tekstu w złożony sposób. Opublikuję kolejną odpowiedź pokazującą, jak to zrobićawk
.Możesz zamiast tego użyć a
,
lub|
a, to zajmie to jako separator i technicznie możesz użyć wszystkiegoze strony podręcznika
Jak widać, powinieneś zacząć od \ przed separatorem na początku, możesz użyć go jako separatora.
z dokumentacji http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022- Polecenie :
Przykład:
sed -e 'somevar|s|foo|bar|'
echo "Hello all" | sed "s_all_user_"
echo "Hello all" | sed "s,all,user,"
echo "Hello/ World" | sed "s,Hello/,Neo,"
źródło
/
i zignoruje to z/
radością, jak właśnie wskazałem .. w rzeczywistości możesz nawet poszukać go i zastąpić ciągiem >>> edytowałem z przykładem >>> te rzeczy nie są tak bezpieczne i zawsze znajdziesz mądrzejszegosed
po pierwsze, jaki jest twój projekt?bash
jest przeznaczony do manipulacji ciągami. W ogóle, w ogóle, w ogóle. Służy do manipulacji plikami i koordynacji poleceń . Zdarza się, aby mieć jakiś wbudowany w poręcznej funkcji ciągów, ale bardzo ograniczone i nie bardzo szybko, jeśli w ogóle to najważniejsze robisz. Zobacz „Dlaczego używanie pętli powłoki do przetwarzania tekstu jest uważane za złą praktykę?” Niektóre narzędzia, które są przeznaczone do przetwarzania tekstu są w kolejności od najprostszych do najbardziej wydajne: , i Perl.sed
awk
Jeśli jest oparty na linii i tylko jeden wiersz do zastąpienia, zalecam wcześniejsze przygotowanie samego pliku za pomocą wiersza zastępującego
printf
, przechowywanie pierwszego wiersza w polused
wstrzymania i upuszczanie go w razie potrzeby. W ten sposób nie musisz się martwić o znaki specjalne. (Jedynym założeniem tutaj jest to, że$VAR
zawiera jeden wiersz tekstu bez żadnych nowych linii, co już powiedziałeś w komentarzach.) Poza nowymi liniami, VAR może zawierać cokolwiek i to zadziała niezależnie.printf '%s\n'
wypisze zawartość$VAR
jako ciąg dosłowny, niezależnie od jego zawartości, a następnie nowy wiersz. (echo
w niektórych przypadkach zrobi inne rzeczy, na przykład jeśli treść$VAR
zaczyna się od myślnika - zostanie to zinterpretowane jako przekazanie flagi opcjiecho
).Nawiasy klamrowe są używane do dodania wyjścia
printf
do zawartości posomefile
jej przekazaniused
. Ważna jest tutaj biała spacja oddzielająca nawiasy klamrowe, podobnie jak średnik przed zamykającym nawias klamrowy.1{h;d;};
jakosed
komenda będzie przechowywać pierwszą linię tekstu wsed
„s miejsca przechowywania , a następnied
suĹ linię (zamiast drukowanie)./KEYWORD/
stosuje następujące działania do wszystkich wierszy, które zawierająKEYWORD
. Akcja jestg
et, która pobiera zawartość przestrzeni wstrzymania i upuszcza ją w miejsce przestrzeni wzorca - innymi słowy, całą bieżącą linię. (To nie jest zamiana tylko części linii.) Nawiasem mówiąc, przestrzeń wstrzymania nie jest opróżniana, po prostu kopiowana do przestrzeni wzorów, zastępując wszystko, co tam jest.Jeśli chcesz zakotwiczyć wyrażenie regularne, aby nie pasowało ono do linii, która zawiera tylko SŁOWO KLUCZOWE, ale tylko linię, w której nie ma nic innego oprócz KEYWORD, dodaj początek linii anchor (
^
) i koniec linii anchor ($
) do twoje wyrażenie regularne:źródło
Możesz użyć ukośnika odwrotnego do ukośników w zastępującym ciągu, używając rozszerzenia parametru podstawienia wzorca Basha. Jest to trochę bałagan, ponieważ ukośniki do przodu również muszą być poprzedzone przez Bash.
wynik
Państwo mogli umieścić interpretacji parametrów bezpośrednio do komendy sed:
ale myślę, że pierwsza forma jest nieco bardziej czytelna. I oczywiście, jeśli zamierzasz ponownie użyć tego samego wzorca zastępowania w wielu poleceniach sed, sensowne jest, aby wykonać konwersję tylko raz.
Inną opcją byłoby użycie skryptu napisanego w awk, perl lub Python, lub program w C, do wykonania zamiany zamiast używania sed.
Oto prosty przykład w Pythonie, który działa, jeśli zastępowane słowo kluczowe jest pełną linią w pliku wejściowym (nie licząc nowej linii). Jak widać, jest to zasadniczo ten sam algorytm, co w przykładzie Bash, ale bardziej efektywnie odczytuje plik wejściowy.
źródło
\x
sekwencje specjalne. Lub użyć programu, który może obsłużyć dowolne dane wejściowe, jak wspomniałem w poprzednim akapicie.Tak poszedłem:
w moim przypadku działa to świetnie, ponieważ moje słowo kluczowe samo w sobie znajduje się w wierszu. Gdyby słowo kluczowe było w linii z innym tekstem, to nie zadziałałoby.
Wciąż chciałbym wiedzieć, czy istnieje prosty sposób, który nie wymaga kodowania własnego rozwiązania.
źródło
echo
. Użyjprintf
zamiast tego. A przetwarzanie tekstu w pętli powłoki to zły pomysł.read
jest raczej powolny. Służy do przetwarzania interaktywnych danych wejściowych użytkownika, a nie przetwarzania plików tekstowych. Jest powolny, ponieważ odczytuje stdin char po char, wykonując wywołanie systemowe dla każdego char.printf "hi\n"
sprawi, że printf wydrukuje nowy wiersz, podczas gdyecho "hi\n"
wydrukuje go takim, jaki jest.printf
oznacza „format” - pierwszym argumentemprintf
jest specyfikator formatu . Jeśli ten specyfikator%s\n
oznacza „ciąg po znaku nowej linii”, nic w następnym argumencie nie będzie interpretowane ani tłumaczoneprintf
w ogóle . (Powłoka może nadal ją interpretować; najlepiej wstawić wszystko w pojedyncze cudzysłowy, jeśli jest to dosłowny ciąg, lub podwójne cudzysłowy, jeśli chcesz rozszerzenia zmiennej.) Zobacz moją odpowiedź, używającprintf
więcej szczegółów.