kelompok penangkap sed tidak bekerja

27

Saya memiliki serangkaian format [0-9]+\.[0-9]+\.[0-9]. Saya perlu mengekstraksi angka pertama, kedua, dan ketiga secara terpisah. Seperti yang saya pahami, kelompok tangkapan harus mampu melakukan ini. Saya harus bisa menggunakan sed "s/\([0-9]*\)/\1/guntuk mendapatkan nomor pertama, sed "s/\([0-9]*\)/\2/guntuk mendapatkan nomor kedua, dan sed "s/\([0-9]*\)/\3/guntuk mendapatkan nomor ketiga. Namun dalam setiap kasus, saya mendapatkan seluruh string. Mengapa ini terjadi?

Melab
sumber
6
Grup Tangkap menangkap seluruh grup ... bukan elemen individu dalam grup. Anda perlu sesuatu seperti 's/\([0-9]\)\([0-9]\)\([0-9]\).*/\1\2\3/'menangkap nomor individual.
Munir

Jawaban:

45

Kami tidak dapat memberikan jawaban lengkap tanpa contoh masukan Anda, tetapi saya dapat memberi tahu Anda bahwa pemahaman Anda tentang kelompok tangkapan salah. Anda tidak menggunakannya secara berurutan, mereka hanya merujuk pada regex di sisi kiri dari operator substitusi yang sama. Jika Anda menangkap, misalnya /(foo)(bar)(baz)/, maka fooakan \1, barakan \2dan bazakan \3. Anda tidak dapat melakukannya s/(foo)/\1/; s/(bar)/\2/, karena, dalam s///panggilan kedua , hanya ada satu grup yang ditangkap, jadi \2tidak akan ditentukan.

Jadi, untuk menangkap tiga grup digit Anda, Anda perlu melakukan:

sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'

Atau, yang lebih mudah dibaca:

sed -E 's/([0-9]*)\.([0-9]*)\.([0-9]*)/\1 : \2 : \3/'
terdon
sumber
1
Apa manfaatnya melepaskan kurung dalam contoh pertama?
Josh M.
2
@ Josh. Anda perlu melarikan diri agar mereka dapat digunakan untuk menangkap pola. Biasanya /(foo)/sed akan cocok dengan (karakter literal , diikuti oleh foodan kemudian literal ). Jika Anda ingin mengambil grup, Anda harus keluar dari tanda kurung atau menggunakan -Eopsi.
terdon
Saya hampir selalu menggunakan -rbendera jadi saya menganggap itu sebabnya saya belum menemukan ini.
Josh M.
1
@ Josh. ya, -rbendera juga akan melakukan itu, tetapi tidak portabel. GNU sed mendukungnya tetapi banyak yang lain tidak. Itu -Elebih universal.
terdon
9

Contoh:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'
123

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'
456

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'
78

Atau, semuanya:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'
123 : 456 : 78
jai_s
sumber
2

Gunakan Sed dengan -r, --regexp-extended untuk menghindari semua tanda kurung lolos.

echo "1234.567.89" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+)/\1, \2, \3/' 
1234, 567, 89    #output
Surya
sumber