Ganti konten grup regex capture menggunakan sed

16

Saya mencoba mengedit file nginx.conf saya secara terprogram, yang berisi baris seperti ini:

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

yang saya ingin terlihat seperti ini:

        access_log /dev/stdout;

Saya percaya regex ^\s*access_log([^;]*);akan menangkap /var/log/nginx/access.logbagian dalam grup tangkap, tapi saya tidak yakin bagaimana cara benar mengganti kelompok tangkap dengan sed?

Saya sudah mencoba

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

tapi saya mendapatkan kesalahan:

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

jika saya coba sed -rmaka tidak ada kesalahan, tetapi hasilnya tidak seperti yang saya harapkan:

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

Saya mencoba menjadi pintar dengan grup tangkap dan yang lainnya dan tidak mencari langsung "access_log /var/log/nginx/access.log;" dalam hal distribusi mengubah lokasi file log default.

Abe Voelker
sumber
1
sed '/access_log/s|/[^;]\+|/dev/stdout|'
Costas
@ Costas Jika Anda mau menjawabnya, saya akan mendukung Anda karena itu juga berhasil!
Abe Voelker

Jawaban:

16

Beberapa kesalahan di sana.

Pertama, karena sedmenggunakan ekspresi reguler dasar, Anda perlu \(dan \)membuat grup tangkap. The -rberalih memungkinkan diperpanjang ekspresi reguler yang mengapa Anda tidak mendapatkan kesalahan. Lihat Mengapa saya perlu keluar dari karakter regex di sed untuk diartikan sebagai karakter regex? .

Kedua, Anda menempatkan kelompok penangkap di tempat yang salah. Jika saya memahami Anda dengan benar, Anda dapat melakukan ini:

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

Perhatikan penggunaan !sebagai pembatas regex untuk menghindari keharusan melepaskan garis miring ke depan /dev/stdout.

Joseph R.
sumber
Terima kasih, bekerja dengan luar biasa! Saya belum dapat menandai ini sebagai diterima, tetapi akan kembali dalam 9 menit untuk melakukannya.
Abe Voelker
1
@AbeVoelker Terima kasih. Aku senang bisa membantu.
Joseph R.
5

Di regexp Anda, Anda harus tahu bahwa itu \No.adalah referensi kembali ke pola di dalam tanda kurung (). Jadi regexp seharusnya's@^(\s*access_log ).*$@\1/dev/stdout/;@'

Saya bisa menawarkan

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

PETUNJUK: Apakah Anda bermaksud untuk menggunakan /di dalam patern Anda bebas untuk mengubah s///untuk setiap simbol yang Anda inginkan s###misalnya

Costas
sumber
Terima kasih, saya berharap dapat menerima dua jawaban! Saya tidak lagi menyesal tidak sepenuhnya membaca halaman manual sebelum meminta bantuan setelah melihat solusinya.
Abe Voelker
3

Daripada menangkapnya, mengapa tidak mencari saja dan melakukan substitusi? Yaitu:

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

Ia mencari garis yang cocok dengan " access_log" lalu pada garis apa pun yang melakukannya akan menggantikan " /whatever/path/is/there;" dengan " /dev/stdout;"

Jeremy Davis
sumber