Previous Entry Share Next Entry
Про шелл
Ĵonglado
zhtw
Почему (head -n $n; cat) <$file не эквивалентно tail -n -$n $file
Давайте я сначала расскажу, почему можно подумать, что это эквивалентные конструкции.

Очень просто:


(head -n $n; cat) <$file


Что тут происходит? Сначала fork, потом закрывается стандартный ввод, потом открывается $file. Дискриптор при этом выделяется 0-й. Дальше дважды fork/exec. Первый раз для head, второй —для cat.

После fork'а для head'а дочерний процесс имеет копию дискриптора родительского процесса. Это значит, что при закрытии стандартного ввода head'ом, файл не закрывается, ведь у родительского осталась копия дискриптора. И текущая позиция в файле тоже осталась прежней. Fork перед exec для cat'а копирует дискриптор еще один раз и cat продолжает читать с той позиции, где head закончил.

Но это не работает. Точнее это работает, когда ввод происходит из терминала. А если читать данные из файла на диске или еще откуда-нибудь, то нет.

У head'а нет возможности прочитать со ввода ровно заданное число сторк, потому что для этого бы пришлось читать побайтно. Терминал в обычном режиме буферизирует данные как раз построчно. А вот при чтении из файла с диска, размер буфера определяется через stat.

Поэтому head обычно читает больше, чем мы его просим. (На вывод он копирует, конечно же, столько, сколько нужно.)

Как жаль. А ведь такая красивая конструкция!
Tags: ,

?

Log in