Jak zapisać złożony regex do wielokrotnego ponownego użycia w sed?


12

Używając sed, często tworzę raczej skomplikowane i skomplikowane wyrażenia regularne, które muszę dwukrotnie dopasować w pliku. Czy istnieje sposób na zapisanie tego wyrażenia regularnego i odwołanie go dwa razy?

Może coś, co wygląda tak?

sed ' complicated_regex=/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+$/
s/complicated_regex:complicated_regex/simple-output/
' my_file

Aktualizacja: Odpowiedź przedstawiła rozwiązanie polegające na użyciu zmiennej bash. To nie działa Biorąc pod uwagę test.txt.

#test.txt
foo bar
bar foo

I scenariusz

#!/bin/bash

VALUE='foo \([a-z]\+\)'

sed 's/"${VALUE}"/foo happy \1/' test.txt

To powinno dać wynik

foo happy bar
bar foo

Ale zamiast tego pojawia się błąd

sed: -e expression #1, char 24: invalid reference \1 on `s' command's RHS

Jeśli używasz Perla, możesz odwoływać się do poprzednich części wyrażenia w wyrażeniu:perl -pe 's/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+:\1$/simple_output/' my_file
— glenn jackman 21.09.11

1
Kiedy znajdziesz coś zbyt skomplikowanego dla sed, nie wahaj się wybrać awk lub perla.
— Gilles „SO- przestań być zły”,

2
@Cory: Twój przykład działa dobrze, jeśli dobrze zrozumiesz jego składnię. Wciąż masz „zmienną $” zawartą w „pojedynczych cudzysłowach”, która ukrywa ją przed rozszerzeniem powłoki, której się spodziewasz ... powinno byćsed 's/'"${VALUE}"'/foo happy \1/' test.txt
— Peter.O

Odpowiedzi:


7

Możesz użyć zmiennych powłoki:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+'
sed s/^"$complicated_regex":"$complicated_regex"\$/'simple-output'/ my_file

Nie jestem pewien, co miałeś na myśli $i, ale może być konieczne umieszczenie go poza pojedynczymi cudzysłowami:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{'"$i"'}})?)+'

Oczywiście działa to tylko wtedy, gdy sedpolecenie jest wywoływane z powłoki, ale istnieje podobne rozwiązanie z prawie wszystkimi językami programowania. (I nie sądzę, aby można było używać zmiennych w sed
— środku

Hmm. Próbując tego, odniesienia wsteczne wydają się być zepsute. s/$complicated_regex/\1/podaje błąd informujący, że jest to nieprawidłowe odwołanie.
— Cory Klein,

Ach, może moja wina, jestem przyzwyczajony do podstawiania zmiennych zsh. Zobacz zaktualizowaną odpowiedź.
— Stéphane Gimenez,

Będziesz musiał usunąć kotwice ze zmiennej i umieścić je w skrypcie sed:sed "s/^${complicated_regex}:${complicated_regex}\$/simple-output/" my_file
— glenn jackman

Hه! Tak, zapomniałem sprawdzić, czy otrzymałem prawidłową konkatenację wyrażenia regularnego :-)
— Stéphane Gimenez

0

Najłatwiejszym sposobem na dodanie wartości zmiennej powłoki sedi nie martwienie się o to, jak ucieczka w odwrotny ukośnik będzie musiała się zmienić w pozostałej części sedskryptu, jest wypełnienie wszystkiego pojedynczymi cudzysłowami oprócz zmiennej i umieszczenie tego w cudzysłowach.

Wszystkie poniższe przykłady kodu zakładają: VALUE='foo \([a-z]\+\)'

Następujący uszkodzony kod kończy się niepowodzeniem, ponieważ zmienna VALUEnie jest rozwinięta:

sed 's/"${VALUE}"/foo happy \1/' test.txt

Poniższy uszkodzony kod kończy się niepowodzeniem, ponieważ ukośnik odwrotny \1zostaje zjedzony przez powłokę (ponieważ występuje w cudzysłowie, a nie w cudzysłowie), zanim sedgo zobaczy:

sed "s/${VALUE}/foo happy \1/" test.txt

Poniższy kod działa zgodnie z oczekiwaniami:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt

Działa również następujący kod:

sed "s/${VALUE}/foo happy \\1/" test.txt

Podobnie jest w przypadku:

sed s/"${VALUE}"/foo\ happy\ \\1/ test.txt

Ale po co się komplikować? Pojedyncze cudzysłowy wokół sedskryptu sprawiają, że wszystko jest znacznie wyraźniejsze, szczególnie dla guru nie-powłoki-skryptów, który czyta twój kod. Moim ulubionym sposobem jest zrezygnowanie z pojedynczych cudzysłowów z podwójnymi cudzysłowami tylko dla rozszerzenia zmiennej i przejście od razu do pojedynczych cudzysłowów:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt
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.