Наступна команда оболонки повинна була друкувати лише непарні рядки вхідного потоку:
echo -e "aaa\nbbb\nccc\nddd\n" | (while true; do head -n 1; head -n 1 >/dev/null; done)
Але замість цього він просто друкує перший рядок: aaa
.
Те ж не відбувається, коли він використовується з параметром -c
( --bytes
):
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 >/dev/null; done)
Ця команда виводиться 1234512345
як очікувалося. Але це працює тільки в Coreutils реалізації head
утиліти. Реалізація зайнятої програми все ще їсть зайві символи, тому вихід просто 12345
.
Я думаю, що цей конкретний спосіб реалізації зроблений для оптимізації. Ви не можете знати, де закінчується рядок, тому ви не знаєте, скільки символів потрібно прочитати. Єдиний спосіб не споживати зайві символи з вхідного потоку - це читати потік у байті. Але читання з потоку один байт за часом може бути повільним. Тож я думаю, що head
читає вхідний потік на достатньо великий буфер, а потім підраховує рядки в цьому буфері.
Те саме не можна сказати у випадку, коли --bytes
використовується опція. У цьому випадку ви знаєте, скільки байтів вам потрібно прочитати. Тож ви можете прочитати саме таку кількість байтів і не більше того. Реалізація corelibs використовує цю можливість, однак зайнятий не робить, він все ще читає більше байтів, ніж потрібно в буфер. Це, мабуть, робиться для спрощення реалізації.
Отже питання. Чи правильно head
утиліта споживає більше символів з вхідного потоку, ніж було запропоновано? Чи існує якийсь стандарт для утиліт Unix? І якщо є, чи визначає це поведінка?
PS
Ви повинні натиснути, Ctrl+C
щоб зупинити команди вище. Утиліти Unix не спрацьовують при читанні далі EOF
. Якщо ви не хочете натискати, ви можете скористатися більш складною командою:
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 | [ `wc -c` -eq 0 ] && break >/dev/null; done)
яку я не використовував для простоти.