Ogólnie rzecz biorąc, zwykle szukam sed
przetwarzania tekstu - szczególnie w przypadku dużych plików - i zwykle unikam robienia tego rodzaju rzeczy w samej powłoce.
Myślę jednak, że to może się zmienić. Grzebałem man ksh
i zauważyłem to:
<#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.
Sceptycznie odnosząc się do użyteczności w świecie rzeczywistym, postanowiłem to wypróbować. Zrobiłem:
seq -s'foo bar
' 1000000 >file
... dla miliona linii danych, które wyglądają jak:
1foo bar
...
999999foo bar
1000000
... i zmierzyli się z sed
:
p='^[^0-8]99999.*bar'
for c in "sed '/$p/q'" "ksh -c ':<##@(~(E)$p)'"
do </tmp/file eval "time ( $c )"
done | wc -l
Tak więc oba polecenia powinny dostać się do paska 999999foo, a ich implementacja dopasowania wzorca musi oceniać co najmniej początek i koniec każdej linii w tym celu. Muszą także zweryfikować pierwszy znak względem zanegowanego wzoru. To prosta sprawa, ale ... Wyniki nie były zgodne z oczekiwaniami:
( 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
używa ERE tutaj i sed
BRE. ksh
Wcześniej robiłem to samo i wzór powłoki, ale wyniki nie różniły się.
W każdym razie jest to dość znacząca rozbieżność - ksh
przewyższa sed
10 razy. Czytałem wcześniej, że David Korn napisał własną bibliotekę io i implementuje ją w ksh
- być może jest to związane? - ale ja nic o tym nie wiem. Jak to się dzieje, że skorupa robi to tak dobrze?
Jeszcze bardziej zdumiewające jest dla mnie to, że ksh
naprawdę pozostawia swoje przesunięcie tam, gdzie o to prosisz. Aby uzyskać (prawie) to samo z (GNU) sed
, musisz użyć -u
- bardzo wolno .
Oto test 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
bije grep
tutaj - ale nie zawsze - są prawie związane. Mimo to jest to całkiem doskonałe i ksh
zapewnia spojrzenie z wyprzedzeniem, zanimhead
rozpocznie się mecz.
Wydaje mi się, że to po prostu zbyt piękne, aby mogło być prawdziwe. Co te polecenia robią inaczej pod maską?
Och, i najwyraźniej nie ma tu nawet podpowłoki:
ksh -c 'printf %.5s "${<file;}"'
źródło
pattern
wyrażenie regularne czy prostszy wzór powłoki?Odpowiedzi:
Ksh nie tylko korzysta z sfio, ale korzysta z własnego niestandardowego przydziału pamięci.
Niemniej jednak przypuszczam, że sfio robi różnicę w tym przypadku. Właśnie próbowałem uruchomić twój przykład pod kontrolą i widzę, że wywołania ksh odczytują / zapisują ~ 200 razy (bloki 65 KB), a sed robi to ~ 3400 razy (bloki 4 KB). Z sed -u mój laptop prawie się stopił, odczyty są wykonywane na bajt i zapisywane na wiersz. Ksh simple używa lseek. Grep używa odczytu ~ 400 razy (bloki 32 KB).
źródło
ksh
silnik regex jest wydajny jak jego io? W każdym razie dziękuję bardzo za odpowiedź. Przepraszam twojego laptopa. A co z niestandardowym alokatorem pamięci? Czy masz coś więcej na ten temat?