Jadi, secara umum, saya cenderung mencari sed
pengolahan teks - terutama untuk file besar - dan biasanya menghindari melakukan hal-hal di shell itu sendiri.
Saya pikir, itu mungkin berubah. Saya mencari-cari man ksh
dan memperhatikan ini:
<#pattern Seeks forward to the beginning of the
next line containing pattern.
<##pattern The same as <# except that the por‐
tion of the file that is skipped is
copied to standard output.
Skeptis tentang kegunaan dunia nyata, saya memutuskan untuk mencobanya. Aku melakukannya:
seq -s'foo bar
' 1000000 >file
... untuk sejuta baris data yang terlihat seperti:
1foo bar
...
999999foo bar
1000000
... dan mengadu itu sed
seperti:
p='^[^0-8]99999.*bar'
for c in "sed '/$p/q'" "ksh -c ':<##@(~(E)$p)'"
do </tmp/file eval "time ( $c )"
done | wc -l
Jadi kedua perintah harus mendapatkan bar 999999foo dan implementasi pencocokan pola mereka harus mengevaluasi setidaknya awal dan akhir setiap baris untuk melakukannya. Mereka juga harus memverifikasi char pertama terhadap pola yang dinegasikan. Ini adalah hal yang sederhana, tapi ... Hasilnya tidak seperti yang saya harapkan:
( sed '/^[^0-8]99999.*bar/q' ) \
0.40s user 0.01s system 99% cpu 0.419 total
( ksh -c ':<##@(~(E)^[^0-8]99999.*bar)' ) \
0.02s user 0.01s system 91% cpu 0.033 total
1999997
ksh
menggunakan ERE di sini dan sed
BRE. Saya melakukan hal yang sama dengan ksh
dan pola shell sebelumnya tetapi hasilnya tidak berbeda.
Bagaimanapun, itu perbedaan yang cukup signifikan - ksh
mengungguli sed
10 kali lipat. Saya telah membaca sebelumnya bahwa David Korn menulis io lib-nya sendiri dan mengimplementasikannya ksh
- mungkin ini terkait? - tapi saya tidak tahu apa-apa tentang itu. Bagaimana cangkangnya melakukan ini dengan sangat baik?
Bahkan yang lebih menakjubkan bagi saya adalah ksh
benar - benar meninggalkan offset tepat di tempat Anda memintanya. Untuk mendapatkan (hampir) sama dengan (GNU) sed
Anda harus menggunakan -u
- sangat lambat .
Inilah tes grep
v ksh
.:
1000000 #grep + head
( grep -qm1 '^[^0-8]99999.*bar'; head -n1; ) \
0.02s user 0.00s system 90% cpu 0.026 total
999999foo bar #ksh + head
( ksh -c ':<#@(~(E)^[^0-8]99999.*bar)'; head -n1; ) \
0.02s user 0.00s system 73% cpu 0.023 total
ksh
berdetak di grep
sini - tetapi tidak selalu - mereka cukup terikat. Namun, itu cukup bagus, dan ksh
memberikan head
masukan lookahead - dimulai sebelum pertandingan.
Sepertinya terlalu bagus untuk menjadi kenyataan, kurasa. Apa yang dilakukan perintah-perintah ini secara berbeda di bawah tenda?
Oh, dan ternyata tidak ada subkulit di sini:
ksh -c 'printf %.5s "${<file;}"'
sumber
pattern
ekspresi reguler atau pola shell yang lebih sederhana?Jawaban:
Tidak hanya ksh menggunakan sfio tetapi juga menggunakan pengalokasi memori kustom sendiri.
Namun demikian, dugaan saya adalah sfio membuat perbedaan dalam kasus ini. Saya baru saja mencoba menjalankan contoh Anda di bawah strace dan dapat melihat bahwa panggilan ksh membaca / menulis ~ 200 kali (65 blok KB) sementara sed melakukannya ~ 3400 kali (blok 4 KB). Dengan sed -u laptop saya hampir meleleh, pembacaan dilakukan per byte dan menulis per baris. Ksh sederhana menggunakan lseek. Grep menggunakan baca ~ 400 kali (32 blok KB).
sumber
ksh
mesin regex seefisien io? Bagaimanapun, terima kasih banyak atas jawabannya. Saya minta maaf untuk laptop Anda. Bagaimana dengan pengalokasi memori khusus? Apakah Anda memiliki lebih dari itu?