Як точно працює трубопровід / перенаправлення в Linux?


1

У мене є ці три приклади перенаправлення stdin / stdout, лише один з них працює так, як і призначений. Я хотів би, якщо хтось може мені це пояснити.

Мета - сортувати вміст у file1 та зберегти зміни до того самого файлу.

  1. сортувати файл1 | tee file1> / dev / null --------> Це працює

  2. сортувати файл1 | tee file1 --------> Зміст file1 буде стерто

  3. сортувати файл1 | tee file1> file2 --------> Зміст file1 буде стерто

PS. трійник копіює стандартний вхід у кожен файл, а також на стандартний вихід.

Що змушує працювати перший приклад?


4
Тільки для запису: якщо ви використовуєте GNU sortви можете використовувати -oопцію: sort file1 -o file1.
— Аркадіуш Драбчик

Дякую за цю інформацію, я її не знав. Але я подав команду сортування як приклад, опція -o не постачається з іншими командами, такими як sed і cut. Тож для того, щоб маніпулювати вмістом файлу та вносити зміни до нього, змусить мене використовувати методи трубопроводу / перенаправлення, які я не знаю, як вони концептуально працюють. Як ви бачите вище, я не можу зрозуміти механізм, який змусив працювати перший, а не два інших.
— користувач3464156

Сторінки man для bash and tee пропонують широкі приклади, які, як правило, характерні для встановленої програми, і детально розглядають побічні ефекти таких речей, як noclobber .....
— Дон Саймон,

Відповіді:


0

Згідно з моїми тестами на Debian Wheezy, всі 3 сценарії можуть призвести до обох результатів (файл1 сортується і записується назад до себе АБО нічого не сортується і нічого не записується у файл1.

Я вважаю, що це нормальна поведінка і пов'язане з тим, як Linux працює з файлами. Подумайте про команду - команда сортування починає читати файл1 і негайно відправляє його вихід у tee. Трійник зчитує вихід, записує його назад у файл1 та друкує його в / dev / null. У випадку, якщо сортування досить швидке, щоб прочитати весь файл1, tee отримує відсортований вихід. Але у випадку, якщо трійник заблокує файл, він стирає його (ти завжди стирає вихідний файл, за винятком випадків, коли використовується опція додавання), і це майже все, що відбувається у всіх ваших 3 сценаріях.

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

Я рекомендую наступну процедуру:

cat file1 | sort > /tmp/sorting.tmp; mv /tmp/sorting.tmp file1

Якщо ви хочете побачити відсортований вихід на stdout, зробіть це так:

cat file1 | sort | tee /tmp/sorting.tmp; mv /tmp/sorting.tmp file1

Недоцільно дозволити 2 різні команди, що працюють з 1 файлом у багатопроцесорних системах - ви ніколи не можете бути впевнені, яка з них виконується першою. У єдиній потоковій системі поведінка була б різною - послідовною.


Спасибі Томасе, твоя відповідь була дуже зрозумілою. Тепер я розумію, що моя проблема не полягала в сортуванні, а в тому, як працюють Linux і перенаправлення в Linux. Хоча @jcoppens майже відповів те саме, але не був конкретним, як ви.
— користувач3464156

2

Я сумніваюся, що така поведінка передбачувана (і, безумовно, від цього не залежатиме). teeКоманда , ймовірно , починається новий процес , щоб відправити свій внесок в «інше» призначення. Операційна система буде «буферувати» вихід, поки не досягне точки, де він створює файл призначення і записує свій тимчасовий буфер у файл. Точний момент, коли це станеться (і замінить джерело), ​​ймовірно, залежить від:

  • Розмір файлу та наявна пам'ять для буфера
  • Час, що минув
  • Якщо вхід з труби teeзакінчується

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

Не забувайте, що bash - це лише інтерпретатор команд користувача: це лише shellнавколо операційної системи для перетворення намірів користувача в системні виклики.

І це теж задокументовано ! Або цей лист , який вирішує подібні проблеми. Або ця нитка StackOverflow . Або цей потік сервера за замовчуванням .

Зверніть увагу , що це може статися і з перенаправленням stdin: якщо взяти входи команди з файлу $ myprog < commandfile. Якщо myprogпише в commandfile, немає гарантії, що всі commandfileкоманди будуть виконані .

Дійсно базовою аналогією було б щось подібне до цього списку інструкцій:

- Execute the instructions step by step
- Dip this instruction list in a bucket of black paint
- Type in the following commands:
  find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
  | grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'

Я б уявив, що ти зробиш копію спочатку? (команда взята з Посібника з розширеного сценарію Bash )


Гаразд, але чому перший приклад завжди працює, а два інших - ні? Особливо, коли перший, теоретично, відповідає третьому. ps: - Усі три приклади використовують один і той же файл, тому розмір однаковий і буфер.
— користувач3464156

Перевірте, чи він досі працює з більшим файлом - понад 64 КБ або 128 КБ. Перший і третій сильно відрізняються. Перший перенаправляє вихідний екран на / dev / null, що дуже швидко, а третій надсилає його в реальний файл, який передбачає велику роботу - відкриття, буферизацію, закриття та інші адміністративні роботи - і включає доступ до диска .
— jcoppens

Але все ж повинні існувати правила, які керують способом інтерпретації команд bash, і в трьох моїх прикладах ніхто ще не проясняв, як їх інтерпретують баш, який зробив перший, що дає результат, який відрізняється від інших, незважаючи на технічно те саме (приклади).
— користувач3464156

Коментар був занадто довгим, я додав його до відповіді.
— jcoppens

До речі, ви протестували з більшими файлами?
— jcoppens

0

Отже, ви хочете, щоб оригінальний вміст файла залишався, додаючи файл із змінами?

tee over пише за замовчуванням, спробуйте використати прапор -a, щоб додати файл із змінами.


1
Насправді я не хочу додавати, я хочу перезаписати. Це працює з першим прикладом. Я хочу знати механізм, що лежить в основі трубопроводів / перенаправлення, який приводить лише перший приклад до роботи, а не два інших.
— користувач3464156

сортувати файл1 | tee file1 вносить зміни до file1 та записує їх у файл. Не знаєте, про що ви просите?
— Азума

сортувати файл1 | tee file1 видалить вміст file1
— user3464156

0
sort file1 | tee file1 > tmp && mv file1 original && mv tmp file1

Ви можете записати файл у заповнювач, перейменувати оригінал на резервну копію, а потім перемістити його в оригінал.


1
зміна file2 на tmp насправді змусила його працювати, але повернувшись до моїх прикладів, ви можете побачити, що у мене вже є рішення. Моє запитання полягає в тому, як трубопроводи / перенаправлення працюють у вищезазначених моїх прикладах, тому лише одна з них працює правильно. Іншими словами, я хочу зрозуміти поведінку цього.
— користувач3464156
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.