Як точно працює трубопровід / перенаправлення в 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.