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 -d
dihilangkan 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
nl
dapat 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 -ha
berarti nomor semua baris tajuk dan -bn
berarti tidak ada garis tubuh - seperti yang dimulai dalam keadaan tubuh .
Sampai aku belajar aku ini digunakan untuk menggunakan nl
untuk masukan apapun, tapi setelah menyadari bahwa nl
keluaran kekuatan mendistorsi menurut default -d
elimiter \:
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 nl
bisa sangat berguna diterapkan dalam hal lain - seperti ini - jika Anda hanya memodifikasi inputnya hanya sedikit - seperti yang saya lakukan dengan di sed
atas.
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 nl
angka baris itu menyisipkan sejumlah karakter ke dalam kepala masing-masing. Untuk garis-garis itu tidak bernomor - bahkan kosong - selalu cocok dengan indent dengan memasukkan ( -w
jumlah -s
idth + 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 nl
akan membagi inputnya menjadi bagian-bagian logis untuk Anda, dan bahwa Anda dapat menyisipkan -s
tring 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 nl
bukan aplikasi target Anda, maka GNU sed
dapat melakukan e
xecute 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 sed
mengumpulkan input dalam ruang pola hingga cukup untuk berhasil melewati subtitusi T
est dan berhenti b
peternakan kembali ke :l
abel. Ketika itu terjadi, itu e
xecutes nl
dengan 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 b
ranched 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 sed
dicoba cocok - jadi perintah ini menggantikan seluruh @@.*start
baris sebagai nl <<\\@@
gantinya.
:l;N
- The
:
perintah mendefinisikan label cabang - di sini saya menetapkan satu nama :l
abel. The N
perintah ext menambahkan baris berikutnya dari input ke ruang pola diikuti oleh \n
karakter ewline. Ini adalah salah satu dari hanya beberapa cara untuk mendapatkan \n
garis di sed
ruang pola - \n
karakter garis adalah pembatas pasti untuk sed
der 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 \n
segera diikuti dengan @@.*end
menandai bagian paling akhir $
dari ruang pola. Ketika itu bertindak, itu menggantikan seluruh string yang cocok dengan grup \1
pertama , atau .\(
\)
\n@@
Tl
- yang
T
perintah 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 \n
ewline ditambahkan ke ruang pola yang tidak cocok dengan pembatas akhir Anda, T
perintah est gagal dan bercabang kembali ke :l
abel, yang menghasilkan sed
menarik N
garis ekst dan mengulang sampai berhasil.
e
Ketika substitusi untuk pertandingan akhir berhasil dan skrip tidak bercabang kembali untuk T
est gagal , sed
akan e
xecute perintah yang tampak l
seperti 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 read
loop, tetapi untuk alasan yang bagus. Shell - (terutama bash
shell) - 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 read
dibuat untuk tes input yang sangat baik - untuk return
informasi 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 read
menarik garis. Jika berhasil, ini berarti loop belum menekan EOF dan karenanya dalam case
cocok dengan pembatas mulai , do
blok segera dieksekusi. Lain, printf
cetak $line
itu read
dan sed
dipanggil.
sed
akan p
mematahkan setiap baris sampai bertemu dengan penanda awal - ketika ia q
menggunakan input sepenuhnya. The -u
beralih nbuffered diperlukan untuk GNU sed
karena bisa buffer agak rakus sebaliknya, tetapi - sesuai dengan spec - lain POSIX sed
s harus bekerja tanpa pertimbangan khusus - asalkan <infile
adalah file biasa.
Ketika sed
q
uits pertama , shell mengeksekusi do
blok loop - yang memanggil orang lain sed
yang 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
paste
kemudian 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
, head
dan sed
untuk 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.
nl
tidak harus mengakumulasi negara . Lihatnl -d
dan periksaman
/info
halaman untuk informasi tentangnl
's bagian pembatas .