Яка різниця між "Перенаправленням" та "Трубою"?


204

Це питання може здатися трохи дурним, але я не можу реально побачити різницю між перенаправленням і трубами.

Перенаправлення використовується для перенаправлення stdout / stdin / stderr, наприклад ls > log.txt.

Труби використовуються для подачі виводу команди як вхід до іншої команди, наприклад ls | grep file.txt.

Але чому для одного і того ж є два оператори?

Чому б не просто написати, ls > grepщоб пропустити висновок, чи це не просто своєрідне перенаправлення? Що мені не вистачає?

Відповіді:


223

Труба використовується для передачі виводу іншій програмі або утиліті .

Перенаправлення використовується для передачі виводу у файл або потік .

Приклад: thing1 > thing2vsthing1 | thing2

thing1 > thing2

  1. Ваша оболонка запустить програму з назвою thing1
  2. Все, що thing1виводиться, буде розміщено у файлі під назвою thing2. (Примітка - якщо thing2існує, вона буде перезаписана)

Якщо ви хочете передати висновок з програми thing1на програму під назвою thing2, ви можете зробити наступне:

thing1 > temp_file && thing2 < temp_file

який би

  1. запустити програму з назвою thing1
  2. збережіть вихід у файл з назвою temp_file
  3. запустіть програму з назвою thing2, роблячи вигляд, що людина на клавіатурі temp_fileвводила вміст як вхід.

Однак це незграбно, тому вони зробили труби як простіший спосіб зробити це. thing1 | thing2робить те саме, що іthing1 > temp_file && thing2 < temp_file

EDIT, щоб надати більше детальних запитань у коментарі:

Якщо >спробувати бути як «перейти до програми», так і «написати у файл», це може спричинити проблеми в обох напрямках.

Перший приклад: Ви намагаєтесь записати у файл. Уже існує файл з таким ім'ям, який ви хочете перезаписати. Однак файл виконується. Імовірно, він намагатиметься виконати цей файл, передаючи вхід. Вам доведеться зробити щось на зразок записати вихід у нове ім'я файлу, а потім перейменувати файл.

Другий приклад: як зазначав Флоріан Дієш, що робити, якщо в системі є ще одна команда з тим самим іменем (тобто в шляху виконання). Якщо ви мали намір створити файл із цим іменем у вашій поточній папці, ви застрягли б.

По-третє: якщо ви неправильно введете команду, вона не попередить вас, що команда не існує. Прямо зараз, якщо ви введете, ls | gerp log.txtвін вам скаже bash: gerp: command not found. Якщо >мається на увазі і те, і інше, він просто створить новий файл для вас (тоді попередити, що він не знає, що з цим робити log.txt).


Дякую. Ви згадали, thing1 > temp_file && thing2 < temp_fileщо робити простіше з трубами. Але чому б не використати повторно >оператора для цього, наприклад, thing1 > thing2для команд thing1та thing2? Чому додатковий оператор |?
Джон Тріпвуд

1
"Візьміть висновок і запишіть його у файл" - це інша дія, ніж "Візьміть вихід і передайте його іншій програмі". Я відредагую більше думок у своїй відповіді ...
Девід Онелл

1
@JohnThreepwood Вони мають різні значення. Що робити, якщо, наприклад, я хотів щось переспрямувати до імені файлу less? thing | lessі thing > lessвони абсолютно різні, як і різні речі. Те, що ви пропонуєте, створило б неоднозначність.
Darkhogg

Чи точно сказати, що "thing1> temp_file" - це просто синтаксичний цукор для "thing1 | tee temp_file"? З моменту дізнання про трійку я майже ніколи не використовую переадресації.
Шрідхар Сарнобат

2
@ Шрідхар-Сарнобат ні, teeкоманда робить щось інше. teeзаписує вихід на екран ( stdout) і у файл. Перенаправлення робить лише файл.
Девід Онелл

22

Якщо значення значення foo > barзалежатиме від того, чи існує команда з ім'ям, barяка б зробила використання перенаправлення набагато важчим і більш схильним до помилок: Кожен раз, коли я хочу переспрямувати файл, я спершу повинен був перевірити, чи є така команда, як мій цільовий файл.


Це може бути проблемою, лише якщо ви пишете barв каталог, який є частиною вашої $PATHзмінної env. Якщо ви знаходитесь у чомусь подібному / bin, то ot може бути проблемою. Але навіть тоді barповинен був мати набір виконавчих дозволів, щоб оболонка перевіряла не просто пошук виконавчого файлу, barа фактично змогла його виконати. І якщо проблема полягає у перезаписі наявного файлу, nocloberопція оболонки повинна запобігати перезапису існуючих файлів у переадресації.
Сергій Колодяжний

13

З посібника з адміністрування систем Unix та Linux:

Перенаправлення

Оболонка інтерпретує символи <,> та >> як вказівки щодо перегрупування вводу або виводу команди у файл або з нього .

Труби

Для підключення STDOUT однієї команди до STDIN іншої використовуйте | символ, широко відомий як труба.

Отже, моя інтерпретація така: Якщо це командування командувати, використовуйте трубу. Якщо ви виходите з файлу або з нього, використовуйте переадресацію.


12

Існує важлива різниця між двома операторами:

  1. ls > log.txt -> Ця команда надсилає вихід у файл log.txt.

  2. ls | grep file.txt-> Ця команда надсилає висновок ls команді grep через використання pipe ( |), і команда grep шукає file.txt на вході, наданому їй попередньою командою.

Якщо вам довелося виконати те саме завдання, використовуючи перший сценарій, то це було б:

ls > log.txt; grep 'file.txt' log.txt

Таким чином, труба (з |) використовується для надсилання виводу в іншу команду, тоді як перенаправлення (з >) використовується для перенаправлення виводу в якийсь файл.


3

Існує велика синтаксична різниця між ними:

  1. Переадресація - це аргумент до програми
  2. Труба розділяє дві команди

Ви можете думати про переадресовує , як це: cat [<infile] [>outfile]. Це означає, що порядок не має значення: cat <infile >outfileте саме, що cat >outfile <infile. Ви навіть можете змішати переспрямування з іншими аргументами: cat >outfile <infile -bі cat <infile -b >outfileвони прекрасно чудові. Також ви можете нанизувати більш ніж один вхід або вихід (входи будуть читатися послідовно і всі вихідні дані будуть записані в кожен вихідний файл): cat >outfile1 >outfile2 <infile1 <infile2. Ціль або джерело переспрямування може бути або ім'ям файлу, або іменем потоку (як & 1, принаймні в bash).

Але труби повністю відокремлюють одну команду від іншої команди, їх не можна змішувати з аргументами:

[command1] | [command2]

Труба приймає все написане на стандартний вихід з команди1 та надсилає його на стандартний вхід команди2.

Ви також можете комбінувати трубопроводи та перенаправлення. Наприклад:

cat <infile >outfile | cat <infile2 >outfile2

Перший catбуде читати рядки з infile, потім одночасно записувати кожен рядок у outfile та надсилати його другому cat.

У другому cat, стандартний вхід спочатку зчитує з труби (вміст infile), потім читає з infile2, записуючи кожен рядок у outfile2. Після запуску цього файлу outfile буде копією infile, а outfile2 міститиме infile, а потім infile2.

Нарешті, ви насправді робите щось дійсно схоже на ваш приклад, використовуючи перенаправлення "тут рядок" (лише сімейство bash) та зворотні посилання:

grep blah <<<`ls`

дасть такий самий результат, як і

ls | grep blah

Але я думаю, що версія переспрямування спочатку прочитає весь вихід ls в буфер (в пам'яті), а потім подасть цей буфер, щоб зібрати один рядок за один раз, тоді як конвеєрна версія буде приймати кожен рядок з ls у міру появи, і передати цю лінію на греп.


1
Nitpick: замовлення має значення при переадресації, якщо ви перенаправляєте один fd на інший: echo yes 1>&2 2>/tmp/blah; wc -l /tmp/blah; echo yes 2>/tmp/blah 1>&2; wc -l /tmp/blahДалі, перенаправлення до файлу використовуватиме лише останнє перенаправлення. echo yes >/tmp/blah >/tmp/blah2буде писати лише в /tmp/blah2.
муру

2
Перенаправлення насправді не є аргументом до програми. Програма не знатиме і не піклується, куди йде її вихід (або надходить вхід). Це просто спосіб сказати Башу, як впорядкувати речі перед запуском програми.
Алоїз Магдал

3

Примітка. Відповідь відображає моє власне розуміння цих механізмів, накопичене під час дослідження та читання відповідей однолітками на цьому веб-сайті та unix.stackexchange.com , і оновлюватиметься з часом. Не соромтеся задавати питання або запропонувати в коментарях покращення. Я також пропоную вам спробувати побачити, як функціонують систематичні виклики в оболонці з straceкомандою. Крім того, будь ласка, не лякайте поняття внутрішніх або системних дзвінків - вам не потрібно знати або вміти ними користуватися, щоб зрозуміти, як оболонка робить речі, але вони, безумовно, допомагають зрозуміти.

TL; DR

  • |Труби не асоціюються із записом на диску, тому не мають вхідного числа файлової системи диска (але мають inode у віртуальній файловій системі pipefs у просторі ядра), але перенаправлення часто включають файли, які мають записи диска і тому мають відповідні inode.
  • pipe не lseek()в змозі, тому команди не можуть прочитати деякі дані, а потім перемотатися назад, але коли ви переспрямовуєте >або, <як правило, це файл, який lseek()може об'єктивувати, тому команди можуть переміщатись, як не завгодно.
  • перенаправлення - це маніпуляції з дескрипторами файлів, яких може бути багато; Труби мають лише два дескриптори файлів - один для лівої команди та один для правої команди
  • перенаправлення на стандартні потоки та труби буферні.
  • труби майже завжди включають вилки і тому в них задіяні пари процесів; переадресації - не завжди, хоча в обох випадках дескриптори файлів у результаті передаються у спадок підпроцесами.
  • Труби завжди з'єднують дескриптори файлів (пари), перенаправлення - або використовують ім'я шляху або дескриптори файлів.
  • Труби - це метод міжпроцесорної комунікації, тоді як перенаправлення - це лише маніпуляції з відкритими файлами або файловими об'єктами
  • обидва використовують dup2()системні виклики під кришкою, щоб забезпечити копії дескрипторів файлів, де відбувається фактичний потік даних.
  • перенаправлення можна застосовувати "глобально" за допомогою execвбудованої команди (див. це і це ), тому якщо ви виконаєте exec > output.txtкожну команду, output.txtз цього часу випишете. |Труби застосовуються лише для поточної команди (що означає або просту команду, або допоміжну оболонку, seq 5 | (head -n1; head -n2)або складні команди.
  • Коли переадресація робиться для файлів, такі речі, як echo "TEST" > fileі echo "TEST" >> fileобидва, використовують open()у цьому файлі syscall ( див. Також ) та отримують від нього дескриптор файлу, щоб передати його dup2(). Труби |використовують тільки pipe()і dup2()систематично.

  • Що стосується команд, що виконуються, перетворення та переадресація - це не більше, ніж дескриптори файлів - файлоподібні об'єкти, до яких вони можуть записувати сліпо або керувати ними внутрішньо (що може спричинити несподівані поведінки; aptнаприклад, прагне навіть не записувати на stdout якщо він знає, що є перенаправлення).

Вступ

Щоб зрозуміти, як ці два механізми відрізняються, необхідно зрозуміти їх основні властивості, історію, що стоїть за ними, та їх коріння в мові програмування на С. Насправді, важливо знати, що таке дескриптори файлів, а також як dup2()і як працюють pipe()системні виклики lseek(). Шелл розуміється як спосіб зробити ці механізми абстрактними для користувача, але копання глибше, ніж абстракція, допомагає зрозуміти справжню природу поведінки оболонки.

Витоки перенаправлення та труби

Згідно зі статтею пророчих петрогліфів Денніса Рітче , труби виникли із внутрішньої пам’ятки 1964 року Малкольма Дугласа Макілроя в той час, коли вони працювали над операційною системою Multics . Цитата:

Щоб висловити свої найсильніші проблеми:

  1. Ми повинні мати деякі способи з'єднання таких програм, як садовий шланг - вкрутити в інший сегмент, коли це стає необхідним, щоб масажувати дані іншим способом. Це також шлях ІО.

Що очевидно, це те, що в той час програми були здатні записувати на диск, однак це було неефективно, якщо вихід був великим. Процитуючи пояснення Брайана Керніган у відео Unix Pipeline :

По-перше, вам не доведеться писати одну велику масову програму - у вас є існуючі менші програми, які вже можуть виконувати частини роботи ... Інше - можливо, що кількість даних, які ви обробляєте, не підійде, якби Ви зберегли його у файлі ... тому що пам’ятайте, ми повернулися в ті часи, коли диски з цими речами мали, якщо пощастило, мегабайт або два дані ... Тож конвеєр ніколи не повинен був інстанціювати весь вихід .

Таким чином, концептуальна різниця очевидна: труби - це механізм змушування програм спілкуватися між собою. Перенаправлення - це спосіб написання файлу на базовому рівні. В обох випадках оболонка робить ці дві речі легкими, але під кришкою все відбувається багато.

Заглиблення: систематичні виклики та внутрішня робота оболонки

Почнемо з поняття дескриптора файлу . Дескриптори файлів в основному описують відкритий файл (будь то файл на диску, або в пам'яті, або анонімний файл), який представлений цілим числом. Два стандартних потоку даних (stdin, stdout, stderr) є дескрипторами файлів 0,1 та 2 відповідно. Звідки вони беруться? Ну а в командах оболонки дескриптори файлів успадковуються від свого батьківського - оболонки. І це взагалі вірно для всіх процесів - дочірній процес успадковує дескриптори файлів батьків. Для демонів прийнято закривати всі спадкові дескриптори файлів та / або перенаправляти на інші місця.

Повернутися до перенаправлення. Що це насправді? Це механізм, який повідомляє оболонці підготувати дескриптори файлів для команди (оскільки перенаправлення виконуються оболонкою перед запуском команди) і вказує їх там, де користувач запропонував. Стандартне визначення вихідного перенаправлення

[n]>word

Що [n]є номер дескриптора файлу. Коли ви робите, echo "Something" > /dev/nullчисло 1 мається на увазі там, і echo 2> /dev/null.

Під кришкою це робиться шляхом дублювання дескриптора файлу через dup2()системний виклик. Візьмемо df > /dev/null. Оболонка створить дочірній процес, де він dfпрацює, але перед цим він відкриється /dev/nullяк дескриптор файлу №3, і dup2(3,1)буде виданий, що робить копію дескриптора файлу 3, а копія буде 1. Ви знаєте, як у вас є два файли file1.txtі file2.txt, а коли у cp file1.txt file2.txtвас буде два однакові файли, але ви можете ними маніпулювати самостійно? Це якось те саме, що відбувається тут. Часто ви можете побачити, що перед запуском, bashбуде dup(1,10)потрібно зробити дескриптор файлу копіювання №1, який є stdout(і ця копія буде fd №10), щоб потім відновити його. Важливо зазначити, що, враховуючи вбудовані команди(які є частиною самої оболонки і не мають файлу ні в /binіншому місці), ні простими командами в неінтерактивній оболонці , оболонка не створює дочірнього процесу.

І тоді у нас є такі речі, як [n]>&[m]і [n]&<[m]. Це дублюючі дескриптори файлів, який той самий механізм, що і dup2()зараз у синтаксисі оболонки, зручно доступний для користувача.

Однією з важливих речей, які слід зазначити про переадресацію, є те, що їх порядок не визначений, а є важливим для того, як оболонка інтерпретує те, що хоче користувач. Порівняйте наступне:

# Make copy of where fd 2 points , then redirect fd 2
$ ls -l /proc/self/fd/  3>&2  2> /dev/null
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
lrwx------ 1 runner user 64 Sep 13 00:08 3 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/29/fd

# redirect fd #2 first, then clone it
$ ls -l /proc/self/fd/    2> /dev/null 3>&2
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
l-wx------ 1 user user 64 Sep 13 00:08 3 -> /dev/null
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/31/fd

Практичне використання їх у сценаріях оболонок може бути багатогранним:

та багато інших.

Сантехніка з pipe()іdup2()

Отже, як створюються труби? Через pipe()syscall , який буде приймати як вхід масив (ака-список), який називається pipefdз двох елементів типу int(ціле число). Ці два цілі числа є дескрипторами файлів. pipefd[0]Буде прочитати кінець труби і pipefd[1]буде кінець запису. Тож у df | grep 'foo', grepотримаємо копію pipefd[0]та dfотримаємо копію pipefd[1]. Але як ? Звичайно, з магією dup2()syscall. Бо dfв нашому прикладі, скажімо, pipefd[1]є №4, тому оболонка зробить дитину, зробіть dup2(4,1)(пам’ятаєте мій cpприклад?), А потім execve()дійсно запустіть df. Природно,dfбуде успадковано дескриптор файлу №1, але він не буде знати, що він більше не вказує на термінал, а насправді fd №4, що є фактично кінцем запису труби. Природно, те ж саме відбуватиметься, за grep 'foo'винятком різної кількості дескрипторів файлів.

Тепер цікаве запитання: чи можемо ми зробити також труби, які перенаправляють fd # 2, а не просто fd №1? Так, насправді це те, що |&робить у баш. Стандарт POSIX вимагає командного мови оболонки для підтримки df 2>&1 | grep 'foo'синтаксису для цієї мети, але bashробить |&так само.

Важливо зазначити, що труби завжди мають дескриптори файлів. Існує FIFOабо названа труба , яка має ім'я файлу на диску, і ми дамо вам використовувати його як файл, але веде себе як труба. Але |типи труб називають анонімною трубою - вони не мають імені файлів, оскільки вони справді просто два об'єднані між собою об’єкти. Те, що ми не маємо справи з файлами, також має важливе значення: труби не lseek()в змозі. Файли, або в пам'яті, або на диску, є статичними - програми можуть використовувати lseek()системний виклик, щоб перейти до байта 120, потім назад до байта 10, а потім вперед до кінця. Труби не є статичними - вони послідовні, і тому ви не можете перемотати дані, отримані з нихlseek(). Це те, що дає зрозуміти деяким програмам, якщо вони читають з файлу або з файлу, і тому вони можуть внести необхідні корективи для ефективної роботи; іншими словами, progможна виявити , якщо я cat file.txt | progабо prog < input.txt. Справжнім прикладом роботи є хвіст .

Інші дві дуже цікаві властивості труб полягають у тому, що вони мають буфер, який в Linux становить 4096 байт , і вони насправді мають файлову систему, як визначено у вихідному коді Linux ! Вони не просто об'єкт для передачі даних навколо, вони самі є структурою даних! Насправді, оскільки існує файлова система pipefs, яка управляє і трубами, і FIFO, труби мають номер inode у відповідній файловій системі:

# Stdout of ls is wired to pipe
$ ls -l /proc/self/fd/  | cat  
lrwx------ 1 user user 64 Sep 13 00:02 0 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:02 1 -> pipe:[15655630]
lrwx------ 1 user user 64 Sep 13 00:02 2 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:02 3 -> /proc/22/fd
# stdin of ls is wired to pipe
$ true | ls -l /proc/self/fd/0
lr-x------ 1 user user 64 Sep 13 03:58 /proc/self/fd/0 -> 'pipe:[54741]'

На Linux труби однонаправлені, як і перенаправлення. На деяких Unix-подібних реалізаціях - є двонаправлені труби. Хоча з магією сценаріїв оболонок, ви можете робити двонаправлені труби і в Linux .

Дивитися також:


2

Щоб додати до інших відповідей, є і тонка семантична різниця - наприклад, труби закриваються легше, ніж переадресації:

seq 5 | (head -n1; head -n1)                # just 1
seq 5 > tmp5; (head -n1; head -n1) < tmp5   # 1 and 2
seq 5 | (read LINE; echo $LINE; head -n1)   # 1 and 2

У першому прикладі, коли перший виклик headзавершується, він закриває трубу та seqприпиняється, тому для другого немає вводу head.

У другому прикладі голова споживає перший рядок, але коли він закриває власну stdin трубку , файл залишається відкритим для наступного дзвінка.

Третій приклад показує, що якщо ми використовуємо readдля уникнення закриття труби, вона все ще доступна в рамках підпроцесу.

Таким чином, "потік" - це те, через що ми перекладаємо дані через (stdin тощо), і в обох випадках однаковий, але труба з'єднує потоки з двох процесів, де перенаправлення з'єднує потоки між процесом і файлом, тож ви Ви можете бачити джерело подібності та відмінності.

PS Якщо ви настільки цікаві та / або здивовані тими прикладами, як я, ви можете скористатися подальшим використанням, trapщоб побачити, як процеси вирішуються, наприклад:

(trap 'echo seq EXITed >&2' EXIT; seq 5) | (trap 'echo all done' EXIT; (trap 'echo first head exited' EXIT; head -n1)
echo '.'
(trap 'echo second head exited' EXIT; head -n1))

Іноді перший процес закривається перед тим, 1як друкується, іноді після цього.

Також мені було цікаво використовувати exec <&-для закриття потоку від перенаправлення, щоб наблизити поведінку труби (хоча і з помилкою):

seq 5 > tmp5
(trap 'echo all done' EXIT
(trap 'echo first head exited' EXIT; head -n1)
echo '.'
exec <&-
(trap 'echo second head exited' EXIT; head -n1)) < tmp5`

"коли перший дзвінок на голову закінчується, він закриває трубку" Це насправді неточно з двох причин. Один, (head -n1; head -n1) - це допоміжна оболонка з двома командами, кожна з яких успадковує прочитаний кінець труби як дескриптор 0, і, таким чином, для підрозділу І кожна команда має дескриптор файлу відкритим. Друга причина, ви можете бачити, що з strace -f bash -c 'seq 5 | (голова -n1; голова -n1) '. Тож перша глава закриває лише свою копію дескриптора файлу
Сергій Колодяжний

Третій приклад також є неточним, оскільки він readспоживає лише перший рядок (це один байт для 1та новий рядок). seqвідправлено загалом 10 байт (5 чисел та 5 нових рядків). Тож у буфері труби залишається 8 байт, і тому другий headпрацює - у буфері труби все ще доступні дані. Btw, голова виходить, лише якщо там прочитано 0 байтів, ніби якhead /dev/null
Сергій Колодяжний

Дякуємо за роз’яснення. Я правильно розумію, що під seq 5 | (head -n1; head -n1)час першого дзвінка спорожняється труба, тож вона все ще існує у відкритому стані, але немає даних для другого виклику head? Тож різниця у поведінці між трубою та переадресацією полягає в тому, що головка витягує всі дані з труби, але лише 2 рядки з файлової ручки?
Джуліан де Баль

Це правильно. І це щось, що можна побачити за допомогою straceкоманди, яку я дав у першому коментарі. З перенаправленням, tmp-файл знаходиться на диску, що робить його вигідним (тому що вони використовують lseek()syscall - команди можуть стрибати навколо файлу з першого байта до останнього, як тільки вони хочуть. Але труби послідовні і не шукаються. Тому єдиний спосіб для голови зробити це робота - прочитати все спочатку, або якщо файл великий - нанесіть на нього частину оперативної пам’яті за допомогою mmap()дзвінка. Я одного разу зробив своє tailв Python і наткнувся на таку саму проблему.
Сергій Колодяжний,

Також важливо пам’ятати, що зчитувальний кінець труби (дескриптор файлу) надається спочатку підпакеті (...), і нижня оболонка зробить копію власного stdin для кожної команди всередині (...). Таким чином, вони технічно зчитуються з одного об’єкта. Спочатку head думає, що це читає з власного stdin. По-друге, headдумає, що у нього є свій стдин. Але насправді їх fd # 1 (stdin) - це просто копія того ж fd, який читається в кінці труби. Також я опублікував відповідь, тому, можливо, це допоможе з’ясувати речі.
Сергій Колодяжний

1

Я сьогодні зіткнувся з проблемою в C. По суті, труби мають різну семантику для переадресації, навіть коли вони надсилаються stdin. Дійсно, я думаю, що зважаючи на відмінності, труби повинні йти куди-небудь, крім того stdin, щоб, stdinі давайте може називати це stdpipe(щоб зробити довільний диференціал), можна обробляти різними способами.

Розглянемо це. При підключенні однієї програми до іншої програма, fstatсхоже, повертає нуль, оскільки st_sizeнезважаючи на ls -lha /proc/{PID}/fdте, що є файл При перенаправлення файлу це не так ( по крайней мере , на Debian wheezy, stretchі jessieванілі і Убунту 14.04, 16.04ваніль.

Якщо ви cat /proc/{PID}/fd/0з перенаправленням зможете повторити читання стільки разів, скільки вам подобається. Якщо ви зробите це за допомогою труби, ви помітите, що вдруге, коли ви виконуєте завдання послідовно, ви не отримаєте однакового результату.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.