Jakie znaki muszę uciec, używając sed w skrypcie sh?

248

Weź następujący skrypt:

#!/bin/sh
sed 's/(127\.0\.1\.1)\s/\1/' [some file]

Jeśli spróbuję uruchomić to w sh( dashtutaj), to się nie powiedzie z powodu nawiasów, które należy uciec. Ale nie muszę uciekać przed odwrotnymi ukośnikami (między oktetami lub w \slub \1). Jaka jest tutaj reguła? A kiedy potrzebuję użyć {...}lub [...]? Czy jest lista tego, co robię i nie muszę uciekać?

obrzydliwie
źródło
1
Oto funkcja bash do konwertowania ścieżek do użycia z SED:function sedPath { path=$((echo $1|sed -r 's/([\$\.\*\/\[\\^])/\\\1/g'|sed 's/[]]/\[]]/g')>&1) } #Escape path for use with sed
user2428118
Dura lex, sed sed
Nemo

Odpowiedzi:

281

Istnieją dwa poziomy interpretacji: skorupa i sed.

W powłoce wszystko między pojedynczymi cudzysłowami jest interpretowane dosłownie, z wyjątkiem samych pojedynczych cudzysłowów. Możesz efektywnie utworzyć pojedynczy cytat między pojedynczymi cytatami, pisząc '\''(zamknij pojedynczy cytat, jeden dosłowny pojedynczy cytat, otwórz pojedynczy cytat).

Sed używa podstawowych wyrażeń regularnych . W BRE, aby traktować je dosłownie, znaki $.*[\^należy cytować, poprzedzając je odwrotnym ukośnikiem, z wyjątkiem wewnętrznych zestawów znaków ( […]). Litery, cyfry i (){}+?|nie mogą być cytowane (możesz uciec od cytowania niektórych z nich w niektórych implementacjach). Sekwencje \(, \), \n, aw niektórych implementacjach \{, \}, \+, \?, \|i inne backslash + alfanumeryczne mają specjalne znaczenie. Możesz uciec od nie cytowania $^niektórych pozycji w niektórych implementacjach.

Ponadto przed odwrotnym użyciem /wyrażeń regularnych potrzebujesz odwrotnego ukośnika . Możesz wybrać alternatywny znak jako separator, pisząc np. s~/dir~/replacement~Lub \~/dir~p; będziesz potrzebować odwrotnego ukośnika przed separatorem, jeśli chcesz uwzględnić go w BRE. Jeśli wybierzesz postać, która ma specjalne znaczenie w BRE i chcesz ją dosłownie uwzględnić, potrzebujesz trzech odwrotnych ukośników; Nie polecam tego, ponieważ może zachowywać się inaczej w niektórych implementacjach.

W skrócie, dla sed 's/…/…/':

  • Napisz wyrażenie regularne między pojedynczymi cudzysłowami.
  • Użyj, '\''aby skończyć z jednym cytatem w wyrażeniu regularnym.
  • Umieść ukośnik odwrotny przed $.*/[\]^i tylko te znaki (ale nie wewnątrz wyrażeń w nawiasach). (Technicznie nie należy wprowadzić odwrotny ukośnik przed ]ale nie wiem od implementacji, że traktuje ]i \]różnie poza wyrażeń nawiasów).
  • W wyrażeniu nawiasowym, -aby być traktowanym dosłownie, upewnij się, że jest ono pierwsze lub ostatnie ( [abc-]lub [-abc]nie [a-bc]).
  • W wyrażeniu nawiasowym, ^aby być traktowanym dosłownie, upewnij się, że nie jest ono pierwsze (użyj [abc^], nie [^abc]).
  • Aby dołączyć ]do listy znaków pasujących do wyrażenia ^w nawiasach, ustaw go jako pierwszy znak (lub pierwszy po nim dla zestawu negacji): []abc]lub [^]abc](nie [abc]]ani[abc\]] ).

W tekście zastępczym:

  • &i \należy je cytować, poprzedzając je odwrotnym ukośnikiem, podobnie jak separator (zwykle /) i znaki nowej linii.
  • \po którym następuje cyfra ma specjalne znaczenie. \po której następuje litera ma specjalne znaczenie (znaki specjalne) w niektórych implementacjach, a \po niej inne znaki \club w czależności od implementacji.
  • Z pojedynczymi cudzysłowami wokół argumentu ( sed 's/…/…/'), użyj, '\''aby wstawić pojedynczy cytat w tekście zastępczym.

Jeśli wyrażenie regularne lub tekst zastępczy pochodzi ze zmiennej powłoki, pamiętaj o tym

  • Wyrażenie regularne to BRE, a nie dosłowny ciąg.
  • W wyrażeniu regularnym nowa linia musi być wyrażona jako \n(która nigdy nie będzie pasować, chyba że masz inny sedkod dodający znaki nowej linii do obszaru szyku). Należy jednak pamiętać, że w niektórych sedimplementacjach nie będzie działał w wyrażeniach nawiasów .
  • W tekście zastępczej &, \i nowe linie muszą być cytowane.
  • Separator musi być cytowany (ale nie wewnątrz wyrażeń w nawiasach).
  • Użyj cudzysłowów dla interpolacji: sed -e "s/$BRE/$REPL/".
Gilles
źródło
Uciekając od znaku wieloznacznego (*), można użyć podwójnego ukośnika odwrotnego ( \\*). Przykład:echo "***NEW***" | sed /\\*\\*\\*NEW\\*\\*\\*/s/^/#/
danger89
43

Problem, którego doświadczasz, nie wynika z interpolacji powłoki i ucieczki - to dlatego, że próbujesz użyć rozszerzonej składni wyrażeń regularnych bez podania opcji -rlub --regexp-extended.

Zmień linię sed z

sed 's/(127\.0\.1\.1)\s/\1/' [some file]

do

sed -r 's/(127\.0\.1\.1)\s/\1/' [some file]

i będzie działać tak, jak wierzę, że masz zamiar.

Domyślnie sed używa podstawowych wyrażeń regularnych (styl grep), które wymagałyby następującej składni:

sed 's/\(127\.0\.1\.1\)[ \t]/\1/' [some file]
R Perrin
źródło
Znów miałem ten problem i zapomniałem przewinąć w dół, aby znaleźć rozwiązanie, które głosowałem ostatnio. Dzięki jeszcze raz.
isaaclw
Wielkie dzięki. Dodanie -rjako opcji było w moim przypadku konieczne.
HelloGoodbye
15

O ile nie chcesz interpolować zmiennej powłoki w wyrażeniu sed, użyj pojedynczych cudzysłowów dla całego wyrażenia, ponieważ powodują one interpretację wszystkiego między nimi, w tym odwrotnych ukośników.

Więc jeśli chcesz, aby sed zobaczył s/\(127\.0\.1\.1\)\s/\1/umieszczanie pojedynczych cudzysłowów wokół niego, a powłoka nie dotknie nawiasów ani odwrotnych ukośników. Jeśli potrzebujesz interpolować zmienną powłoki, umieść tylko tę część w podwójnych cudzysłowach. Na przykład

sed 's/\(127\.0\.1\.1\)/'"$ip"'/'

Pozwoli to zaoszczędzić kłopotu z zapamiętywaniem, które metaznaki powłoki nie są poprzedzane podwójnymi cudzysłowami.

Kyle Jones
źródło
Chcę sedto zobaczyć s/(127\.0\.1\.1)/..., ale umieszczenie tego w skrypcie powłoki w obecnej postaci nie działa. To, co mówisz o powłoce nie dotykającej nawiasów, wydaje się błędne. Zredagowałem moje pytanie, aby je rozwinąć.
detly
3
Powłoka nie dotyka nawiasów. Potrzebujesz backslases, ponieważ sed musi je zobaczyć. sed 's/(127\.0\.1\.1)/IP \1/'kończy się niepowodzeniem, ponieważ sed musi zobaczyć \(i \)dla składni grupy, (a nie i ).
Kyle Jones
facepalm Nie ma go na stronie podręcznika, ale JEST w jakiejś instrukcji online, którą znalazłem. Czy jest to normalne dla wyrażenia regularnego, ponieważ nigdy nie musiałem go używać w bibliotekach wyrażeń regularnych (np. W Pythonie)?
detly
3
W przypadku tradycyjnych poleceń uniksowych istnieją podstawowe wyrażenia regularne i rozszerzone wyrażenia regularne. Szczegóły . sed używa podstawowych wyrażeń regularnych, więc ukośniki odwrotne są potrzebne do składni grupy. Perl i Python wykroczyli poza nawet rozszerzone wyrażenia regularne. Podczas grzebania wokoło znalazłem niezwykle pouczającą tabelę, która ilustruje, jak mętną bramble wyczarowujemy, gdy płynnie mówimy „wyrażenie regularne”.
Kyle Jones
1
Dodałbym również, że jedynym znakiem, którego nie można użyć w pojedynczym cudzysłowie, jest pojedynczy cudzysłów.
enzotib