tr -c \\n 1 <testfile | #first transform every [^\n] char to a 1
grep -nF '' | #next get line numbers
paste -d: - testfile | #then paste it together with itself
sort -t: -nk2,2 #then sort on second field
... dan pemenangnya adalah ... baris 2, sepertinya.
2:1111:4for
4:11111:five!
1:1111111:seven/7
3:11111111:8 eight?
Tetapi masalah dengan itu adalah bahwa setiap baris harus lebih dari dua kali panjang agar bisa berfungsi - jadi LINE_MAX dibelah dua secara efektif. Penyebabnya adalah bahwa ia menggunakan - apa, basis 1? - untuk merepresentasikan panjang garis. Pendekatan serupa - dan mungkin lebih rapi - mungkin untuk mengompres informasi tersebut dalam aliran. Gagasan pertama yang muncul dalam benak saya adalah bahwa saya harus melakukannya unexpand
:
tr -c \\n \ <testfile | #transform all [^\n] to <space>
unexpand -t10 | #squeeze every series of 10 to one tab
grep -nF '' | #and get the line numbers
sed 's/:/!d;=;:/;h;:big #sed compares sequential lines
$P;$!N; /\(:[^ ]*\)\( *\)\n.*\1.*\2/!D #newest line is shorter or...
g;/:./!q;b big' | #not; quit input entirely for blank line
sed -f - -e q testfile #print only first occurrence of shortest line
Cetakan itu ...
2
4for
Satu lagi, hanya sed
:
sed -n '/^\n/D;s/\(.\)\(\n.*\)*/\1/g
$p;h; s// /g;G;x;n;//!g;H;s// /g
G; s/^\( *\)\(\n \1 *\)\{0,1\}\n//
D' <infile >outfile
Sintaksnya sesuai standar - tapi itu bukan jaminan bahwa yang lama sed
akan menangani dengan \(reference-group\)\{counts\}
benar - banyak yang tidak.
Ini pada dasarnya menerapkan regexp yang sama untuk memasukkan berulang kali - yang bisa sangat bermanfaat ketika saatnya untuk mengkompilasi mereka. Pola itu adalah:
\(.\)\(\n.*\)*
Yang cocok dengan string berbeda dengan cara yang berbeda. Sebagai contoh:
string1\nstring2\nstring3
... cocok dengan s
di \1
dan ''
string nol di \2
.
1\nstring2\nstring3
... cocok dengan 1
di \1
dan \nstring2\nstring3
di\2
\nstring2\nstring3
... cocok dengan \n
di \1
dan ''
string nol di \2
. Ini akan bermasalah jika ada peluang \n
ewline terjadi di kepala ruang pola - tetapi /^\n/D
, dan //!g
perintah digunakan untuk mencegah hal ini. Saya memang menggunakan [^\n]
tetapi kebutuhan lain untuk skrip kecil ini membuat portabilitas menjadi perhatian dan saya tidak puas dengan banyak cara yang sering disalahartikan. Plus, .
lebih cepat.
\nstring2
string1
... cocokkan \n
dan s
lagi \1
dan keduanya mendapatkan ''
string nol \2
. Baris kosong tidak cocok sama sekali.
Ketika pola diterapkan secara g
lobal , dua bias - baik bias kiri paling standar maupun bias sisi kanan lebih rendah \n
- berlawanan arah untuk menghasilkan lompatan. Beberapa contoh:
s/\(.\)\(\n.*\)*/\1:\2/g
s/\(.\)\(\n.*\)*/\2\1:/g
s/\(.\)\(\n.*\)*/\1: /g
s/\(.\)\(\n.*\)*/ :\2/g
... jika semua diterapkan (tidak berturut-turut) ke string berikut ...
string1\nstring2
... akan mengubahnya menjadi ...
s:t:r:i:n:g:1:\nstring2
s:t:r:i:n:g:\nstring21:
s:t:r:i:n:g:1:
: : : : : : :\nstring2
Pada dasarnya saya menggunakan regexp untuk selalu hanya menangani baris pertama di setiap pola-ruang yang saya terapkan. Itu memungkinkan saya untuk menyulap dua versi yang berbeda dari kedua jalur yang terpendek-cocok-sejauh-tetap dan yang terbaru tanpa menggunakan loop tes - setiap penggantian yang diterapkan menangani seluruh ruang pola sekaligus.
Versi yang berbeda diperlukan untuk perbandingan string / string literal - jadi harus ada versi setiap baris di mana semua karakter dijamin sama. Tetapi tentu saja jika salah satu dari yang lain benar-benar berakhir menjadi jalur input terpendek yang muncul, maka jalur yang dicetak ke output mungkin harus merupakan versi asli dari jalur tersebut - bukan versi yang telah saya sanitasi / dihomogenisasi untuk kepentingan perbandingan. Jadi saya butuh dua versi masing-masing.
Sangat disayangkan bahwa kebutuhan lain adalah banyak switching buffer untuk menangani yang sama - tetapi setidaknya tidak ada buffer yang melebihi lebih dari empat baris yang diperlukan untuk tetap terkini - dan jadi mungkin itu tidak mengerikan.
Bagaimanapun, untuk setiap siklus, hal pertama yang terjadi adalah transformasi pada baris yang diingat - karena satu-satunya salinan yang benar-benar disimpan adalah yang asli - ke ...
^ \nremembered line$
... dan sesudahnya jalur n
input ext menimpa buffer lama. Jika tidak mengandung setidaknya satu karakter, maka secara efektif diabaikan. Jauh lebih mudahq
menggunakan baris kosong pertama, tetapi, well, data pengujian saya memiliki banyak hal dan saya ingin menangani beberapa paragraf.
Dan jika itu memang mengandung karakter, versi literalnya ditambahkan ke baris yang diingat dan versi perbandingannya ditempatkan di kepala ruang pola, seperti ini:
^ \n \nremembered line\nnew$
Terakhir substitusi diterapkan ke ruang pola itu:
s/^\( *\)\(\n \1 *\)\{0,1\}\n//
Jadi, jika baris baru dapat masuk dalam ruang yang diperlukan untuk memuat baris yang diingat dengan setidaknya satu karakter cadangan, maka dua baris pertama diganti, yang lain hanya yang pertama.
Terlepas dari hasilnya, baris pertama dalam ruang pola selalu D
dihilangkan pada akhir siklus sebelum memulai lagi. Ini berarti bahwa jika baris baru lebih pendek dari yang terakhir ...
new
... dikirim kembali ke subtitusi pertama dalam siklus yang akan selalu dihapus hanya dari karakter baris baru pertama - dan tetap utuh. Tetapi jika tidak maka string ...
remembered line\nnew
... akan memulai siklus berikutnya sebagai gantinya, dan substitusi pertama akan menghapus darinya string ...
\nnew
...setiap saat.
Pada baris terakhir baris yang diingat dicetak ke standar keluar, dan jadi untuk contoh data yang diberikan, ia mencetak:
4for
Tapi, serius, gunakan tr
.