Saya melihat banyak contoh dan halaman manual tentang bagaimana melakukan hal-hal seperti cari-dan-ganti menggunakan sed, awk, atau gawk.
Namun dalam kasus saya, saya memiliki ekspresi reguler yang ingin saya jalankan pada file teks untuk mengekstrak nilai tertentu. Saya tidak ingin melakukan pencarian-dan-ganti. Ini dipanggil dari bash. Mari gunakan contoh:
Contoh ekspresi reguler:
.*abc([0-9]+)xyz.*
Contoh file masukan:
a
b
c
abc12345xyz
a
b
c
Sesederhana kedengarannya, saya tidak tahu cara memanggil sed / awk / gawk dengan benar. Apa yang saya ingin lakukan, adalah dari dalam skrip bash saya:
myvalue=$( sed <...something...> input.txt )
Hal-hal yang saya coba termasuk:
sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing
Jawaban:
Saya
sed
(Mac OS X) tidak bekerja dengan+
. Saya mencoba*
sebagai gantinya dan saya menambahkanp
tag untuk pertandingan pencetakan:Untuk mencocokkan setidaknya satu karakter numerik tanpa
+
, saya akan menggunakan:sumber
+
dan kemudian berhasil untuk saya:sed -n 's/^.*abc\([0-9]\+\)xyz.*$/\1/p'
Anda dapat menggunakan sed untuk melakukan ini
-n
jangan mencetak baris yang dihasilkan-r
ini membuatnya jadi Anda tidak memiliki jalan keluar dari kelompok tangkap parens()
.\1
pertandingan grup tangkap/g
pertandingan global/p
cetak hasilnyaSaya menulis alat untuk diri saya sendiri yang membuat ini lebih mudah
sumber
Saya biasa
perl
membuat ini lebih mudah bagi diri saya sendiri. misalnyaIni menjalankan Perl,
-n
opsi memerintahkan Perl untuk membaca dalam satu baris pada satu waktu dari STDIN dan mengeksekusi kode. The-e
pilihan menentukan instruksi untuk menjalankan.Instruksi menjalankan regexp pada baris yang dibaca, dan jika cocok mencetak konten set bracks (
$1
) pertama.Anda juga dapat melakukan ini dengan beberapa nama file di akhir. misalnya
perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt
sumber
Jika versi Anda
grep
mendukungnya, Anda dapat menggunakan-o
opsi untuk mencetak hanya sebagian dari baris yang cocok dengan regexp Anda.Jika tidak maka inilah yang terbaik yang
sed
bisa saya hasilkan:... yang menghapus / melompati tanpa digit dan, untuk baris yang tersisa, menghapus semua karakter non-digit di depan dan di belakangnya. (Saya hanya menebak bahwa niat Anda adalah mengekstrak nomor dari setiap baris yang berisi satu).
Masalah dengan sesuatu seperti:
.... atau
... apakah itu
sed
hanya mendukung pertandingan "serakah" ... jadi yang pertama. * akan cocok dengan sisa baris. Kecuali kita dapat menggunakan kelas karakter yang dinegasikan untuk mencapai kecocokan yang tidak serakah ... atau versi yangsed
kompatibel dengan Perl atau ekstensi lain ke regex-nya, kita tidak dapat mengekstrak pola persis yang cocok dari dengan ruang pola (garis ).sumber
sed
perintah Anda dengan cara ini:sed -n 's/[^0-9]*\([0-9]\+\).*/\1/p'
grep -o
! Saya mencoba melakukan ini dengansed
dan berjuang dengan kebutuhan saya untuk menemukan banyak kecocokan di beberapa baris. Solusi saya adalah stackoverflow.com/a/58308239/117471Anda dapat menggunakan
awk
denganmatch()
untuk mengakses grup yang diambil:Ini mencoba mencocokkan polanya
abc[0-9]+xyz
. Jika melakukannya, ia menyimpan irisannya dalam larikmatches
, yang item pertamanya adalah blok[0-9]+
. Karenamatch()
mengembalikan posisi karakter, atau indeks, di mana substring tersebut dimulai (1, jika dimulai pada awal string) ,print
tindakan tersebut memicu .Dengan
grep
Anda dapat menggunakan lihat ke belakang dan ke depan:Ini memeriksa pola
[0-9]+
ketika terjadi di dalamabc
danxyz
dan hanya mencetak angka.sumber
perl adalah sintaks terbersih, tetapi jika Anda tidak memiliki perl (tidak selalu ada, saya mengerti), maka satu-satunya cara untuk menggunakan gawk dan komponen regex adalah dengan menggunakan fitur gensub.
keluaran dari file masukan sampel akan
Catatan: gensub menggantikan seluruh regex (di antara //), jadi Anda perlu meletakkan. * Sebelum dan sesudah ([0-9] +) untuk menghilangkan teks sebelum dan sesudah angka dalam substitusi.
sumber
match()
untuk mengakses grup yang diambil. Lihat jawaban saya untuk ini.Jika Anda ingin memilih garis, hapus bit yang tidak Anda inginkan:
Ini pada dasarnya memilih garis yang Anda inginkan
egrep
dan kemudian digunakansed
untuk menghapus bit sebelum dan sesudah nomor.Anda dapat melihat ini beraksi di sini:
Pembaruan: jelas jika situasi Anda sebenarnya lebih kompleks, RE perlu saya modifikasi. Misalnya jika Anda selalu memiliki satu nomor yang terkubur dalam nol atau lebih non-numerik di awal dan akhir:
sumber
Kasus OP tidak menentukan bahwa mungkin ada beberapa kecocokan dalam satu baris, tetapi untuk lalu lintas Google, saya akan menambahkan contoh untuk itu juga.
Karena kebutuhan OP adalah mengekstrak grup dari pola, penggunaan
grep -o
akan membutuhkan 2 lintasan. Tapi, saya masih menganggap ini cara paling intuitif untuk menyelesaikan pekerjaan.Karena waktu prosesor pada dasarnya gratis tetapi keterbacaan manusia sangat berharga, saya cenderung memfaktorkan ulang kode saya berdasarkan pertanyaan, "setahun dari sekarang, menurut pendapat saya apa manfaatnya?" Faktanya, untuk kode yang ingin saya bagikan secara publik atau dengan tim saya, saya bahkan akan terbuka
man grep
untuk mencari tahu apa saja opsi panjang dan menggantinya. Seperti:grep --only-matching --extended-regexp
sumber
Anda bisa melakukannya dengan cangkang
sumber
Untuk awk. Saya akan menggunakan skrip berikut:
sumber
([0-9+])
, ini mengeluarkan seluruh baris.sumber