Bagaimana mendeteksi end of line dengan sed

15

Saya mencari cara untuk hanya melakukan penggantian ketika karakter terakhir adalah baris baru, menggunakan sed.

Contohnya:

lettersAtEndOfLine

diganti, tetapi ini bukan:

lettersWithCharacterAfter&

Karena sedtidak bekerja dengan baik dengan baris baru, itu tidak sesederhana

$ sed -E "s/[a-zA-Z]*\n/replace/" file.txt

Bagaimana ini bisa dicapai?

Matthew D. Scholefield
sumber

Jawaban:

21

Dengan standar sed, Anda tidak akan pernah melihat baris baru dalam teks yang dibaca dari file. Ini karena sedmembaca baris demi baris, dan karena itu tidak ada baris baru di akhir teks dari baris saat ini dalam sedruang pola. Dengan kata lain, sedmembaca data yang dibatasi baris baru, dan pembatas bukanlah bagian dari apa yang seddilihat skrip.

Ekspresi reguler dapat ditambatkan di akhir baris menggunakan $(atau di awal, menggunakan ^). Mengaitkan suatu ekspresi pada awal / akhir suatu garis memaksanya untuk mencocokkan dengan tepat di sana, dan tidak hanya di mana saja pada garis tersebut.

Jika Anda ingin mengganti apa pun yang cocok dengan pola [A-Za-z]*di akhir baris dengan sesuatu, maka jangkar pola seperti ini:

[A-Za-z]*$

... akan memaksanya untuk mencocokkan di akhir baris dan di tempat lain.

Namun, karena [A-Za-z]*$juga tidak cocok dengan apa pun (misalnya, string kosong hadir di akhir setiap baris), Anda perlu memaksakan pencocokan sesuatu , misalnya dengan menentukan

[A-Za-z][A-Za-z]*$

atau

[A-Za-z]\{1,\}$

Jadi, baris perintah sed Anda akan demikian

$ sed 's/[A-Za-z]\{1,\}$/replace/' file.txt

Saya tidak menggunakan -Esakelar di sini karena itu tidak diperlukan. Dengan itu, Anda bisa menulis

$ sed -E 's/[A-Za-z]+$/replace/' file.txt

Ini masalah selera.

Kusalananda
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
Kusalananda
3
sed "s/[a-zA-Z]*$/replace/" input.txt > result.txt

Atau, jalan panjang yang tidak perlu:

Saya sudah tahu, ini bisa dilakukan, masih menggunakan sed, dengan bantuan tr. Anda dapat menetapkan karakter lain untuk mewakili akhir baris. Karakter sementara lain harus digunakan, dalam hal ini "` ". Mari kita gunakan "~" untuk mewakili akhir dari baris:

tr '\n' '`' <input.txt >output.txt
sed -i "s/`/~`/" output.txt
tr '`' '\n' <output.txt >result.txt

Dan kemudian untuk melakukan pencarian dan penggantian yang sebenarnya, gunakan "~" daripada "\ n":

sed -i -E "s/[a-zA-Z]*~/replace/" result.txt

Dan kemudian bersihkan karakter tambahan di baris lain:

sed -i "s/~//" result.txt

Jelas, ini semua bisa disalurkan bersama menghasilkan sesuatu seperti:

tr '\n' '`' <input.txt | sed -e "s/`/~`/" | tr '`' '\n' | sed -E -e "s/[a-zA-Z]*~/replace/" | sed "s/~//" > result.txt
Matthew D. Scholefield
sumber
3
Tidak yakin saya mengerti ... Mengapa Anda tidak berlabuh ke ujung barisan $? miss/[a-zA-Z]*$/replace/
don_crissti
1
2 poin: 1) Anda sebaiknya menggunakan \+daripada *yang terakhir memungkinkan nol huruf pada akhir string; 2) Anda dapat menggunakan kelas karakter [[:alpha:]]. Jadi:sed 's/[[:alpha:]]\+$/replace/' file
glenn jackman
@glennjackman Untuk apa backslash sebelum plus? Bukankah itu cocok dengan karakter tambahan?
Matthew D. Scholefield
1
GNU sed tanpa -ropsi menggunakan sintaks ekspresi reguler ini .
glenn jackman
0

Dari cuplikan kode (rusak) yang Anda poskan, sepertinya Anda juga ingin mengganti baris baru. Jika demikian, regex anchoring dengan sendirinya tidak dapat membantu Anda. Berikut ini adalah solusinya:

sed '/[[:alpha:]]\+$/{N;s/[[:alpha:]]\+\n/replace/}' your_file

Rusak:

  • /[a-zA-Z]\+$/{} berarti menerapkan apa pun yang ada di dalam ikal ke garis yang cocok dengan regex.
  • Regex adalah yang menggunakan penahan seperti yang terlihat pada jawaban Anda sendiri , dimodifikasi untuk memperhitungkan komentar glenn jackman .
  • Di dalam ikal, Nberarti "tambahkan baris berikutnya ke buffer aktif" (apa yang seddisebut 'ruang pola')
  • Akhirnya s///pernyataan itu adalah pengganti Anda. Sekarang berfungsi karena ruang pola berisi dua garis berturut-turut dan baris baru karenanya merupakan bagian darinya.
Joseph R.
sumber
0

Untuk menemukan akhir baris, cukup gunakan tanda-$ :

Tanpa ujung jangkar:

sed -n '/pattern/p' file 

Tanpa ujung jangkar:

sed -n '/pattern$/p' file
Pengguna tidak diketahui
sumber