Труба - це файл, відкритий у внутрішній файловій системі та недоступний як звичайний файл на диску. Він автоматично буферизується лише до певного розміру і з часом блокується після повного заповнення. На відміну від файлів, створених на блокових пристроях, труби ведуть себе як пристрої символів, тому, як правило, не підтримують, lseek()
і дані, прочитані з них, не можуть бути прочитані знову, як це можна зробити зі звичайним файлом.
Тут-рядок - це звичайний файл, створений у змонтованій файловій системі. Оболонка створює файл і зберігає його дескриптор, негайно видаляючи єдине посилання файлової системи (і таким чином видаляючи його), перш ніж він запише / прочитає байт в / з файлу. Ядро буде підтримувати необхідний для файлу простір, поки всі процеси не випустять для нього всі дескриптори. Якщо дитина, що читає з такого дескриптора, має можливість це зробити, його можна перемотати lseek()
і прочитати ще раз.
В обох випадках маркери <<<
і |
представляють дескриптори файлів, а не обов'язково самі файли. Ви можете краще зрозуміти, що відбувається, виконуючи такі речі:
readlink /dev/fd/1 | cat
... або ...
ls -l <<<'' /dev/fd/*
Найбільш суттєвою різницею між двома файлами є те, що тут-рядок / doc - це майже все одночасно - оболонка записує в неї всі дані, перш ніж запропонувати прочитаному дескриптору. З іншого боку, оболонка відкриває трубу на відповідних дескрипторах і відщеплює дітей для управління тими для труби - і так вона записується / читається одночасно на обох кінцях.
Ці відмінності, правда, лише загалом вірні. Наскільки я знаю (що насправді не все так далеко), це стосується майже кожної оболонки, яка обробляє <<<
коротку руку тут-рядка для <<
перенаправлення тут документа за єдиним винятком yash
. yash
, busybox
,dash
, І інші ash
варіанти мають тенденцію до спини тут-документи з трубами, хоча, і тому в цих снарядів там дійсно дуже мало різниці між ними після всього.
Гаразд - два винятки. Тепер, коли я замислююся над цим, ksh93
насправді взагалі не робиш трубку |
, а, швидше, обробляє весь бізнес w / sockets - хоча це і видалений tmp-файл для <<<*
більшості інших. Більше того, він розміщує лише окремі ділянки трубопроводу в середовищі підклітини, яка є своєрідним евфемізмом POSIX, принаймні, він діє як підзаглушка , і навіть не робить вилки.
Справа в тому, що результати @ PSkocik (що дуже корисно) результати тут можуть сильно відрізнятися з багатьох причин, і більшість з них залежить від реалізації. Для налаштування документа тут, найбільшими факторами будуть ${TMPDIR}
тип цільової файлової системи та поточна конфігурація / доступність кешу, а ще більше кількість даних, що підлягають запису. Для труби це буде розмір самої оболонки, оскільки копії робляться для необхідних вилок. Таким чином, bash
це жахливо при налаштуванні конвеєра (включати заміни $(
команд )
) - тому що він великий і дуже повільний, але зksh93
ним навряд чи є різниця взагалі.
Ось ще один маленький фрагмент оболонки, який продемонструє, як оболонка розбивається на підкладки для конвеєра:
pipe_who(){ echo "$$"; sh -c 'echo "$PPID"'; }
pipe_who
pipe_who | { pipe_who | cat /dev/fd/3 -; } 3<&0
32059 #bash's pid
32059 #sh's ppid
32059 #1st subshell's $$
32111 #1st subshell sh's ppid
32059 #2cd subshell's $$
32114 #2cd subshell sh's ppid
Різниця між тим, що конвеєрної розшифровкою pipe_who()
дзвінків і звітом одного запуску в поточній оболонці обумовлена (
подоболочкі в )
зазначеному поведінку витребування PID батьківської оболонки в , $$
коли він розширений. Хоча bash
підрозділи обов язково є окремими процесами, $$
спеціальний параметр оболонки не є надійним джерелом цієї інформації. Тим не менш, дочірня sh
оболонка передплавки не відхиляється, щоб точно повідомити про неї $PPID
.