Następujące polecenie powłoki miało wypisywać tylko nieparzyste linie strumienia wejściowego:
echo -e "aaa\nbbb\nccc\nddd\n" | (while true; do head -n 1; head -n 1 >/dev/null; done)
Ale zamiast po prostu drukuje pierwszą linię: aaa
.
To samo nie dzieje się, gdy jest używane z opcją -c
( --bytes
):
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 >/dev/null; done)
To polecenie generuje 1234512345
zgodnie z oczekiwaniami. Ale działa to tylko w implementacji narzędzia coreutilshead
. BusyBox realizacja nadal spożywa dodatkowe znaki, więc wyjście jest po prostu 12345
.
Wydaje mi się, że ten konkretny sposób implementacji jest wykonywany w celach optymalizacyjnych. Nie możesz wiedzieć, gdzie kończy się linia, więc nie wiesz, ile znaków musisz przeczytać. Jedynym sposobem, aby nie zużywać dodatkowych znaków ze strumienia wejściowego, jest czytanie strumienia bajt po bajcie. Ale czytanie ze strumienia jeden bajt na raz może być powolne. Więc chyba head
czyta strumień wejściowy do wystarczająco dużego bufora, a następnie zlicza wiersze w tym buforze.
Tego samego nie można powiedzieć o przypadku, gdy --bytes
używana jest opcja. W takim przypadku wiesz, ile bajtów musisz odczytać. Możesz więc odczytać dokładnie tę liczbę bajtów i nie więcej. Corelibs implementacja wykorzystuje tę okazję, ale BusyBox jeden nie, to nadal czyta więcej niż bajt wymaganego do bufora. Prawdopodobnie zrobiono to w celu uproszczenia implementacji.
Więc pytanie. Czy to właściwe, że head
narzędzie zużywa więcej znaków ze strumienia wejściowego niż zostało to poproszone? Czy istnieje jakiś standard dla narzędzi uniksowych? A jeśli tak, to czy określa to zachowanie?
PS
Musisz nacisnąć, Ctrl+C
aby zatrzymać powyższe polecenia. Narzędzia uniksowe nie zawodzą przy czytaniu dalej EOF
. Jeśli nie chcesz naciskać, możesz użyć bardziej złożonego polecenia:
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 | [ `wc -c` -eq 0 ] && break >/dev/null; done)
których nie użyłem dla uproszczenia.