Zamień zawartość grupy przechwytywania wyrażeń regularnych za pomocą sed

16

Próbuję programowo edytować mój plik nginx.conf, który zawiera taką linię:

        access_log /var/log/nginx/access.log;

które chcę wyglądać tak:

        access_log /dev/stdout;

Wierzę, że regex ^\s*access_log([^;]*);uchwyci /var/log/nginx/access.logczęść w grupie przechwytywania, ale nie jestem pewien, jak poprawnie zastąpić grupę przechwytywania przez sed?

próbowałem

echo "        access_log /var/log/nginx/access.log;" | sed 's/^\s*access_log([^;]*);/\1\\\/dev\\\/stdout/'

ale pojawia się błąd:

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

jeśli spróbuję, sed -rnie będzie żadnego błędu, ale wynik nie jest zgodny z oczekiwaniami:

 /var/log/nginx/access.log\/dev\/stdout

Staram się być mądry z grupą przechwytywania i tym podobne, a nie szukać bezpośrednio „access_log /var/log/nginx/access.log;” w przypadku gdy dystrybucja zmieni domyślną lokalizację pliku dziennika.

Abe Voelker
źródło
1
sed '/access_log/s|/[^;]\+|/dev/stdout|'
Costas
@Costas Jeśli byś udzielił odpowiedzi, głosowałbym, ponieważ to również działa!
Abe Voelker,

Odpowiedzi:

16

Kilka błędów.

Po pierwsze, ponieważ sedużywa podstawowych wyrażeń regularnych, musisz \(i \)utworzyć grupę przechwytywania. -rPrzełącznik umożliwia rozszerzone wyrażenia regularne, dlatego nie pojawia się błąd. Zobacz Dlaczego muszę uciec znakom regularnym w sed, aby interpretować je jako znaki regularne? .

Po drugie, umieszczasz grupę przechwytywania w niewłaściwym miejscu. Jeśli dobrze cię rozumiem, możesz to zrobić:

sed -e 's!^\(\s*access_log\)[^;]*;!\1 /dev/stdout;!' your_file

Zwróć uwagę na użycie !jako ograniczników wyrażeń regularnych, aby uniknąć konieczności ucieczki przed ukośnikami /dev/stdout.

Joseph R.
źródło
Dzięki, działa cudownie! Nie mogę jeszcze oznaczyć tego jako zaakceptowanego, ale wrócę za 9 minut, aby to zrobić.
Abe Voelker,
1
@AbeVoelker Nie ma za co. Cieszę się że mogłem pomóc.
Joseph R.
5

W swoim wyrażeniu regularnym powinieneś wiedzieć, że \No.jest to odniesienie do wzorca w nawiasach (). Tak więc wyrażenie regularne powinno być's@^(\s*access_log ).*$@\1/dev/stdout/;@'

mogę zaoferować

sed '/access_log/s|/[^;]\+|/dev/stdout|'

WSKAZÓWKA: Niezależnie od tego, czy zamierzasz używać /wewnątrz patern, możesz dowolnie zmieniać s///każdy symbol, s###na przykład

Costas
źródło
Dzięki, chciałbym zaakceptować dwie odpowiedzi! Nie żałuję już, że nie przeczytałem w pełni stron podręcznika, zanim poprosiłem o pomoc po zapoznaniu się z rozwiązaniami.
Abe Voelker,
3

Zamiast go schwytać, dlaczego nie po prostu go znaleźć i dokonać zamiany? To znaczy:

sed "/access_log/ s| /.*;| /dev/stdout;|"

Wyszukuje wiersze pasujące do „ access_log”, a następnie wszystkie wiersze, które to zrobią, zastąpią „ /whatever/path/is/there;” „ /dev/stdout;

Jeremy Davis
źródło