Saya setuju dengan Anda - mungkin ini masalah umum. Namun, beberapa utilitas umum memiliki beberapa fasilitas untuk menanganinya.
nl
nl, misalnya, memisahkan input menjadi halaman logis seperti -ddihilangkan oleh pembatas bagian dua karakter . Tiga kemunculan pada satu garis saja mengindikasikan awal dari sebuah heading , dua body dan satu footer . Ini menggantikan semua yang ditemukan dalam input dengan garis kosong dalam output - yang merupakan satu-satunya baris kosong yang pernah dicetak
Saya mengubah contoh Anda untuk memasukkan bagian lain dan memasukkannya ke dalam ./infile. Jadi sepertinya ini:
line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
@@start
line M
line N
line O
@@end
Kemudian saya menjalankan yang berikut:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end$/@@/' <infile |
nl -d@@ -ha -bn -w1
nldapat dikatakan mengakumulasi keadaan di seluruh halaman logis, tetapi tidak secara default. Alih-alih itu akan memberi nomor baris inputnya sesuai dengan gaya , dan dengan bagian . Jadi -haberarti nomor semua baris tajuk dan -bnberarti tidak ada garis tubuh - seperti yang dimulai dalam keadaan tubuh .
Sampai aku belajar aku ini digunakan untuk menggunakan nluntuk masukan apapun, tapi setelah menyadari bahwa nlkeluaran kekuatan mendistorsi menurut default -delimiter \:saya belajar untuk lebih berhati-hati dengan itu dan mulai menggunakan grep -nF ''untuk input belum teruji sebagai gantinya. Tapi pelajaran lain yang dipelajari hari itu adalah yang nlbisa sangat berguna diterapkan dalam hal lain - seperti ini - jika Anda hanya memodifikasi inputnya hanya sedikit - seperti yang saya lakukan dengan di sedatas.
KELUARAN
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
Inilah beberapa tentang nl- apakah Anda memperhatikan di atas bagaimana semua garis tetapi yang bernomor dimulai dengan spasi? Ketika nlangka baris itu menyisipkan sejumlah karakter ke dalam kepala masing-masing. Untuk garis-garis itu tidak bernomor - bahkan kosong - selalu cocok dengan indent dengan memasukkan ( -wjumlah -sidth + eparator len) * spasi di kepala baris yang tidak bernomor. Ini memungkinkan Anda mereproduksi konten yang tidak bernomor persis dengan membandingkannya dengan konten bernomor - dan dengan sedikit usaha. Ketika Anda mempertimbangkan bahwa nlakan membagi inputnya menjadi bagian-bagian logis untuk Anda, dan bahwa Anda dapat menyisipkan -string sewenang-wenang di kepala setiap baris yang diberi nomor, maka itu akan cukup mudah untuk menangani outputnya:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end/@@/; t
s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'
Cetakan di atas ...
line A
line B
1 do something with the next line!
line X
2 do something with the next line!
line Y
3 do something with the next line!
line Z
line C
line D
1 do something with the next line!
line M
2 do something with the next line!
line N
3 do something with the next line!
line O
GNU sed
Jika nlbukan aplikasi target Anda, maka GNU seddapat melakukan execute perintah shell sewenang-wenang untuk Anda tergantung pada pertandingan.
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
Di atas sedmengumpulkan input dalam ruang pola hingga cukup untuk berhasil melewati subtitusi Test dan berhenti bpeternakan kembali ke :label. Ketika itu terjadi, itu executes nldengan input diwakili sebagai <<dokumen di sini untuk semua sisa-ruang pola.
Alur kerjanya seperti ini:
/^@@.*start$/!b
- jika
^seluruh baris $tidak !tidak /cocok /dengan pola di atas, maka branched dari script dan autoprinted - sehingga dari titik ini kita hanya bekerja dengan serangkaian garis yang dimulai dengan pola.
s//nl <<\\@@/
s//bidang kosong /berarti alamat terakhir yang seddicoba cocok - jadi perintah ini menggantikan seluruh @@.*startbaris sebagai nl <<\\@@gantinya.
:l;N
- The
:perintah mendefinisikan label cabang - di sini saya menetapkan satu nama :label. The Nperintah ext menambahkan baris berikutnya dari input ke ruang pola diikuti oleh \nkarakter ewline. Ini adalah salah satu dari hanya beberapa cara untuk mendapatkan \ngaris di sedruang pola - \nkarakter garis adalah pembatas pasti untuk sedder yang telah melakukannya beberapa saat.
s/\(\n@@\)[^\n]*end$/\1/
- ini
s///ubstitution hanya dapat berhasil setelah start ditemui dan hanya pada kejadian pertama berikut sebuah akhir baris. Ini hanya akan bertindak pada ruang pola di mana garis akhir akhir \nsegera diikuti dengan @@.*endmenandai bagian paling akhir $dari ruang pola. Ketika itu bertindak, itu menggantikan seluruh string yang cocok dengan grup \1pertama , atau .\(\)\n@@
Tl
- yang
Tperintah est cabang untuk label (jika disediakan) jika substitusi yang berhasil belum terjadi sejak terakhir kali line input ditarik ke luar angkasa pola (seperti yang saya lakukan w / N) . Ini berarti bahwa setiap kali \newline ditambahkan ke ruang pola yang tidak cocok dengan pembatas akhir Anda, Tperintah est gagal dan bercabang kembali ke :label, yang menghasilkan sedmenarik Ngaris ekst dan mengulang sampai berhasil.
e
Ketika substitusi untuk pertandingan akhir berhasil dan skrip tidak bercabang kembali untuk Test gagal , sedakan execute perintah yang tampak lseperti ini:
nl <<\\@@\nline X\nline Y\nline Z\n@@$
Anda dapat melihatnya sendiri dengan mengedit baris terakhir yang ada agar terlihat seperti Tl;l;e.
Mencetak:
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
while ... read
Salah satu cara terakhir untuk melakukan ini, dan mungkin cara yang paling sederhana, adalah menggunakan while readloop, tetapi untuk alasan yang bagus. Shell - (terutama bashshell) - biasanya sangat buruk dalam menangani input dalam jumlah besar atau aliran stabil. Ini juga masuk akal - tugas shell adalah menangani input karakter demi karakter dan untuk memanggil perintah lain yang dapat menangani hal-hal yang lebih besar.
Tetapi yang penting tentang perannya adalah bahwa shell tidak boleh read terlalu banyak dari input - itu ditentukan untuk tidak buffer input atau output ke titik yang mengkonsumsi begitu banyak atau tidak menyampaikan cukup pada waktunya sehingga perintah yang dipanggil tidak ada lagi - ke byte. Jadi readdibuat untuk tes input yang sangat baik - untuk returninformasi tentang apakah ada input yang tersisa dan Anda harus memanggil perintah berikutnya untuk membacanya - tetapi itu biasanya bukan cara terbaik untuk pergi.
Berikut ini contoh, bagaimana seseorang dapat menggunakan read dan perintah lain untuk memproses input dalam sinkronisasi:
while IFS= read -r line &&
case $line in (@@*start) :;; (*)
printf %s\\n "$line"
sed -un "/^@@.*start$/q;p";;
esac;do sed -un "/^@@.*end$/q;=;p" |
paste -d: - -
done <infile
Hal pertama yang terjadi untuk setiap iterasi adalah readmenarik garis. Jika berhasil, ini berarti loop belum menekan EOF dan karenanya dalam casecocok dengan pembatas mulai , doblok segera dieksekusi. Lain, printfcetak $lineitu readdan seddipanggil.
sedakan pmematahkan setiap baris sampai bertemu dengan penanda awal - ketika ia qmenggunakan input sepenuhnya. The -uberalih nbuffered diperlukan untuk GNU sedkarena bisa buffer agak rakus sebaliknya, tetapi - sesuai dengan spec - lain POSIX seds harus bekerja tanpa pertimbangan khusus - asalkan <infileadalah file biasa.
Ketika sed quits pertama , shell mengeksekusi doblok loop - yang memanggil orang lain sedyang mencetak setiap baris sampai bertemu dengan penanda akhir . Ini pipa outputnya ke paste, karena mencetak nomor baris masing-masing pada baris mereka sendiri. Seperti ini:
1
line M
2
line N
3
line O
pastekemudian tempelkan bersama-sama pada :karakter, dan seluruh output terlihat seperti:
line A
line B
1:line X
2:line Y
3:line Z
line C
line D
1:line M
2:line N
3:line O
Ini hanya contoh - apa pun bisa dilakukan dalam tes atau melakukan blok di sini, tetapi utilitas pertama tidak boleh mengkonsumsi terlalu banyak input.
Semua utilitas yang terlibat membaca input yang sama - dan mencetak hasilnya - masing-masing pada gilirannya sendiri. Hal semacam ini bisa sulit untuk mendapatkan menguasainya - karena utilitas yang berbeda akan buffer lebih dari yang lain - tetapi umumnya Anda bisa mengandalkan dd, headdan seduntuk melakukan hal yang benar (meskipun, untuk GNU sed, Anda memerlukan cli-switch) dan Anda harus selalu dapat mengandalkan read- karena itu, pada dasarnya, sangat lambat . Dan itulah mengapa loop di atas hanya menyebutnya satu kali per blok input.
nltidak harus mengakumulasi negara . Lihatnl -ddan periksaman/infohalaman untuk informasi tentangnl's bagian pembatas .