Чому оболонка автоматично не фіксує "марне використання кота"? [зачинено]


28

Багато людей використовують однолінійки та скрипти, що містять код уздовж рядків

cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Перший catчасто називають "марним використанням кота", оскільки технічно це вимагає запустити новий процес (часто /usr/bin/cat), коли цього можна було б уникнути, якби команда була

< "$MYFILE" command1 | command2 > "$OUTPUT"

тому що тоді оболонку потрібно лише запустити command1і просто вказати stdinна даний файл.

Чому оболонка не робить це перетворення автоматично? Я відчуваю, що синтаксис "марного використання котячого" легше читати, а шкаралупа повинна мати достатньо інформації, щоб автоматично позбутися від непотрібної кішки. Значення catвизначено в стандарті POSIX, тому оболонці слід дозволити його внутрішньо реалізовувати, а не використовувати бінарний шлях. Оболонка може навіть містити реалізацію лише для точно однієї версії аргументу та відновлюваного до бінарного шляху.


22
Ці команди фактично не є еквівалентними, оскільки в одному випадку stdin - це файл, а в іншому - це труба, тому це не було б строго безпечним перетворенням. Ви можете зробити систему, яка це зробила.
Майкл Гомер

14
Те, що ви не можете уявити собі випадок використання, не означає, що додатку заборонено марно покладатися на вказану поведінку. Отримання помилки lseek- це все-таки визначена поведінка і може спричинити інший результат, різна блокувальна поведінка може бути семантично значущою і т. Д. Можна змінити, якби ви знали, якими є інші команди, і знаєте, що їм все одно, або якщо ви просто не дбали про сумісність на цьому рівні, але користь досить мала. Я думаю, що відсутність вигоди спричиняє ситуацію більше, ніж вартість відповідності.
Майкл Гомер

3
Оболонці абсолютно дозволено реалізувати catсебе, хоча або будь-яку іншу утиліту. Також дозволено знати, як працюють інші утиліти, що належать до системи (наприклад, вона може знати, як поводиться зовнішня grepреалізація, яка постачається із системою ). Це цілком можливо зробити, тому цілком справедливо дивуватися, чому вони цього не роблять.
Майкл Гомер

6
@MichaelHomer, наприклад, він може знати, як поводиться зовнішня реалізація grep, яка поставляється із системою. Отже, оболонка тепер залежить від поведінки grep. І sed. І awk. І du. А скільки сотень, якщо не тисяч інших комунальних служб?
Ендрю Генле

19
Було б досить неприховано моїй оболонці редагувати мої команди для мене.
Azor Ahai

Відповіді:


25

2 команди не еквівалентні: врахуйте обробку помилок:

cat <file that doesn't exist> | less створить порожній потік, який буде переданий в трубопровідну програму ... як такий, у вас з'явиться дисплей, що нічого не показує.

< <file that doesn't exist> less не вдасться відкрити бар, а потім зовсім не відкриватиметься.

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


1
Я відзначу вашу відповідь прийнятою, оскільки вважаю, що це найважливіша різниця між обома синтаксисами. Варіант з catзавжди буде виконувати другу команду в конвеєрі, тоді як варіант з просто перенаправленням вводу взагалі не виконає команду, якщо вхідний файл відсутній.
Мікко Ранталайнен

Однак зауважте, що <"missing-file" grep foo | echo 2він не буде виконуватись, grepале виконає echo.
Мікко Ранталайнен

51

"Марне використання cat" - це більше про те, як ви пишете свій код, ніж про те, що насправді працює під час виконання сценарію. Це свого роду дизайнерський антидіапазон , спосіб вирішити щось, що, ймовірно, можна зробити більш ефективним чином. Це невдача в розумінні того, як найкраще поєднувати дані інструменти для створення нового інструменту. Я б стверджував, що поєднання декількох sedта / або awkкоманд разом у конвеєрі також іноді можна сказати як симптом цієї ж антидіаграми.

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

$ cat script.sh
#!/bin/sh
cat file | cat
$ shellcheck script.sh

In script.sh line 2:
cat file | cat
    ^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.

Змусити оболонку зробити це автоматично буде важко через характер скриптів оболонок. Спосіб виконання сценарію залежить від середовища, успадкованого від його батьківського процесу, та від конкретної реалізації доступних зовнішніх команд.

Оболонка не обов’язково знає, що catтаке. Потенційно це може бути будь-яка команда з будь-якої точки вашого $PATHабо функція.

Якби це була вбудована команда (яка може бути в деяких оболонках), вона мала б можливість реорганізувати конвеєр так, як знала б про семантику його вбудованої catкоманди. Перш ніж робити це, додатково доведеться робити припущення щодо наступної команди в конвеєрі, після оригіналу cat.

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

Це питання схоже (в дуже загальному розумінні) на " Чи є компілятори, які намагаються самостійно виправити помилки синтаксису? " (На сайті Software Engineering StackExchange), хоча це питання, очевидно, стосується синтаксичних помилок, а не марних моделей дизайну. . Ідея про автоматичну зміну коду на основі намірів багато в чому однакова.


Це абсолютно доречно, щоб оболонка знала, що catтаке, а інші команди в трубопроводі (правило як-ніби) і поводяться відповідно, вони просто не мають тут, бо це безглуздо і занадто важко.
Майкл Гомер

4
@MichaelHomer Так. Але також дозволяється перевантажувати стандартну команду з однойменною функцією.
Kusalananda

2
@PhilipCouling Це абсолютно сумісно, ​​доки відомо, що жодна з команд конвеєра не дбає. Оболонці спеціально дозволено замінювати утиліти на вбудовані або функції оболонки, і вони не мають обмежень для середовища виконання, доки зовнішній результат не відрізняється, це дозволено. Для вашого випадку cat /dev/ttyцікавий той, з яким би було б інакше <.
Майкл Гомер

1
@MichaelHomer , якщо зовнішній результат не відрізняється, це дозволено. Це означає, що поведінка всього набору програм, оптимізованих таким чином, ніколи не може змінитися . Це повинно бути певною залежністю залежності.
Ендрю Генле

3
@MichaelHomer Як говорилося в інших коментарях, звичайно, що оболонка цілком відповідає, оскільки , враховуючи вхід ОП, неможливо сказати, що catкоманда насправді робить, не виконуючи її . Для всіх вас (і оболонки) ви знаєте, що ОП має на catсвоєму шляху команду, яка є інтерактивним моделюванням котів, "myfile" - це лише збережений стан гри, command1і command2вони обробляють деяку статистику щодо поточного сеансу гри ...
alephzero

34

Тому що це не марно.

У випадку cat file | cmdfd 0(stdin) of cmdбуде трубою, а у випадку з cmd <fileним може бути звичайний файл, пристрій тощо.

Труба має різну семантику від звичайного файлу, і її семантика не є підмножиною звичайних файлів:

  • звичайний файл не може бути select(2)змінений або poll(2)відредагований змістовно; a select(2)на ньому завжди повернеться "готовим". Розширені інтерфейси, як epoll(2)на Linux, просто не працюватимуть із звичайними файлами.

  • на Linux є системні виклики ( splice(2), vmsplice(2), tee(2)) , які тільки робота на трубах [1]

Оскільки catтак багато використовується, вона може бути реалізована як вбудована оболонка, яка дозволить уникнути зайвого процесу, але як тільки ви розпочали цей шлях, те ж саме можна було б зробити і з більшістю команд - перетворення оболонки на повільніше і незграбніше perlабо python. напевно, краще написати іншу мову сценаріїв з простим у використанні синтаксисом, подібним до труби, для продовження ;-)

[1] Якщо ви хочете, щоб простий приклад не був складений для цього випадку, ви можете подивитися на мою git gist "exec binary from stdin" з деякими поясненнями у коментарі тут . Реалізація catвсередині нього для того, щоб вона працювала без UUoC, зробила б її в 2 або 3 рази більшою.


2
Насправді, ksh93 робить виконання деяких зовнішніх команд , як catвнутрішньо.
jrw32982 підтримує Моніку

3
cat /dev/urandom | cpu_bound_programзапускає read()системні виклики в окремому процесі. Наприклад, у Linux фактична робота процесора з генерування більше випадкових чисел (коли пул порожній) виконується в цьому системному виклику, тому використання окремого процесу дозволяє скористатися окремим ядром CPU для генерації випадкових даних у якості вхідних даних. наприклад, Який найшвидший спосіб створити текстовий файл розміром 1 ГБ, що містить випадкові цифри?
Пітер Кордес

4
Що більш важливо для більшості випадків, це означає lseek, що не буде працювати. cat foo.mp4 | mpv -буде працювати, але ви не можете шукати назад далі, ніж кеш-пам'ять mpv або mplayer. Але з введенням, переспрямованим з файлу, ви можете. cat | mpv -це один із способів перевірити, чи має MP4 свій moovатом на початку файлу, тому він може відтворюватися, не прагнучи до кінця і назад (тобто, якщо він підходить для потокового передачі). Легко уявити інші випадки, коли ви хочете протестувати програму на файли, які не можна шукати, запустивши її /dev/stdinу catпорівнянні з перенаправленням.
Пітер Кордес

Це ще більше вірно при використанні xargs cat | somecmd. Якщо шляхи до файлу виходять за межі буфера команд, вони xargsможуть запускатись catдекілька разів, що призводить до безперервного потоку, при цьому використання xargs somecmdбезпосередньо часто виходить з ладу, оскільки somecmdне може бути запущено у кратних розмірах для досягнення безперебійного результату.
таскет

17

Тому що виявити марну кішку насправді дуже важко.

У мене був сценарій оболонки, де я писав

cat | (somecommand <<!
...
/proc/self/fd/3
...
!) 0<&3

Сценарій оболонки не вдався у виробництві, якщо catбуло видалено, оскільки його викликали через su -c 'script.sh' someuser. Мабуть, зайве catзмусило власника стандартного вводу змінити користувачеві сценарій, що працює, так що повторне відкриття його через /procпрацював.


Цей випадок буде досить простим, оскільки він чітко не відповідає простої моделі, за catякою слідує точно один параметр, тому оболонка повинна використовувати справжній catвиконуваний файл замість оптимізованого ярлика. Хоча хороша думка щодо можливо різних облікових даних або нестандартних стандартів для реальних процесів.
Мікко Ранталайнен

13

tl; dr: оболонки не роблять це автоматично, оскільки витрати перевищують ймовірні вигоди.

Інші відповіді вказували на технічну різницю між тим, що stdin - це труба, і це файл. Маючи це на увазі, оболонка може зробити одне з:

  1. Реалізуйте catяк вбудований, зберігаючи розрізнення файлу v. Pipe. Це дозволить заощадити вартість виконавця і, можливо, вилки.
  2. Виконайте повний аналіз конвеєра, знаючи різні команди, які використовуються, щоб побачити, чи має значення файл / труба, а потім дійте на основі цього.

Далі ви повинні врахувати витрати та переваги кожного підходу. Переваги досить прості:

  1. У будь-якому випадку уникайте виконання (з cat)
  2. У другому випадку, коли можлива заміна переадресації, уникайте вилки.
  3. У тих випадках , коли ви повинні використовувати трубу, це може бути можливо іноді , щоб уникнути навантажувач / vfork, але часто немає. Це тому, що котячий еквівалент повинен працювати одночасно з рештою трубопроводу.

Таким чином, ви економите трохи часу та пам’яті процесора, особливо якщо ви можете уникнути вилки. Звичайно, ви заощаджуєте цей час та пам'ять лише тоді, коли функція фактично використовується. І ви дійсно економите час fork / exec; для великих файлів час - це час введення / виводу (тобто кішка читає файл з диска). Тож вам доведеться запитати: як часто catвикористовується (марно) сценарії оболонки, де продуктивність насправді має значення? Порівняйте його з іншими звичними вбудованими оболонками на кшталт test- важко уявити cat, що використовується (даремно) навіть десяту частину частіше, ніж testвикористовується в важливих місцях. Це здогадка, я не вимірював, що ви хочете зробити перед будь-якою спробою впровадження. (Або подібним чином, попросити когось іншого реалізувати, наприклад, у запиті про функції.)

Далі ви запитуєте: які витрати. Дві витрати, які спадають на думку, - це: (а) додатковий код в оболонці, який збільшує його розмір (і, можливо, використання пам'яті), вимагає додаткових робіт з обслуговування, є ще одним місцем для помилок тощо; та (b) зворотні сюрпризи сумісності, POSIX catзалишає безліч функцій, наприклад, GNU coreutils cat, тому вам доведеться бути уважними, що саме буде catвбудований.

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

  2. Що стосується аналізу трубопроводу, я не думаю, що снаряди роблять щось подібне в даний час (декілька визнають кінець трубопроводу і можуть уникнути вилки). По суті, ви б додавали в оболонку (примітивний) оптимізатор; Оптимізатори часто виявляються складним кодом і джерелом безлічі помилок. І ці помилки можуть дивувати - незначні зміни в скрипті оболонки можуть закінчитися, уникаючи або викликаючи помилку.

Постскрипт: Ви можете застосувати подібний аналіз до своїх марних використання котів. Переваги: ​​легше читати (хоча якщо command1 візьме файл як аргумент, мабуть, ні). Витрати: додатковий форк та exec (і якщо command1 може взяти файл як аргумент, ймовірно, більше заплутаних повідомлень про помилки). Якщо ваш аналіз говорить про те, що ви безкорисливо користуєтесь котом, тоді продовжуйте.


10

catКоманда може прийняти в -якості маркерів для стандартного введення . ( POSIX , " Якщо для файлу є" - ", утиліта cat повинна зчитувати зі стандартного вводу в цій точці послідовності. ") Це дозволяє просто обробляти файл або stdin, якщо в іншому випадку це було б заборонено.

Розглянемо ці два тривіальних альтернативи, де аргумент оболонки $1є -:

cat "$1" | nl    # Works completely transparently
nl < "$1"        # Fails with 'bash: -: No such file or directory'

catКорисний ще один момент , коли він навмисно використовується як неопераційний просто для підтримки синтаксису оболонки:

file="$1"
reader=cat
[[ $file =~ \.gz$ ]] && reader=zcat
[[ $file =~ \.bz2$ ]] && reader=bzcat
"$reader" "$file"

Нарешті, я вважаю, що єдиний час, коли UUOC дійсно може бути правильно викликаний, це коли catвін використовується з ім'ям файлу, який, як відомо, є звичайним файлом (тобто не пристроєм або іменованою трубкою), і що ніякі прапори не даються команді:

cat file.txt

У будь-якій іншій ситуації catможуть знадобитися самі орофіти .


6

Команда cat може робити те, що оболонка не обов'язково може робити (або, принаймні, не може легко зробити). Наприклад, припустимо, що ви хочете надрукувати символи, які в іншому випадку можуть бути невидимими, як-от вкладки, повернення каретки чи нові рядки. Там може бути * спосіб зробити це лише за допомогою команд, вбудованих у оболонки, але я не можу придумати жодної верхньої частини голови. Версія GNU для котів може це зробити з -Aаргументами або -v -E -Tаргументами (хоча я не знаю про інші версії cat). Ви також можете встановити префікс кожного рядка з номером рядка, використовуючи -n(знову ж таки, IDK, якщо це можуть зробити не версії GNU).

Ще одна перевага кота в тому, що вона може легко читати кілька файлів. Для цього можна просто набрати cat file1 file2 file3. Зробити те ж саме з оболонкою, справи стали б складними, хоча ретельно продумана петля, швидше за все, могла б досягти того ж результату. Однак, чи справді ви хочете витратити час на написання такого циклу, коли існує така проста альтернатива? Я не!

Читання файлів з котом, ймовірно, використовує менше процесора, ніж оболонка, оскільки cat - це попередньо складена програма (очевидним винятком є ​​будь-яка оболонка, яка має вбудовану кішку). Під час читання великої групи файлів це може стати очевидним, але я ніколи цього не робив на своїх машинах, тому не можу бути впевненим.

Команда cat також може бути корисною для змушення команди приймати стандартний вхід у випадках, коли це не може. Розглянемо наступне:

echo 8 | sleep

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

echo 8 | sleep $(cat)

Багато снарядів розширять це до sleep 8, і сон вичекатиме 8 секунд до виходу. Ви також можете зробити щось подібне з ssh:

command | ssh 1.2.3.4 'cat >> example-file'

Ця команда з додаванням прикладу-файлу на машині з адресою 1.2.3.4 з тим, що виводиться з "команди".

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


Я закінчував би останнє речення "не легко здійсненним"
Василь Старинкевич,

3

Пам’ятайте, що користувач міг би мати catсвоє, $PATHщо не є саме POSIX cat(але, можливо, якийсь варіант, який міг би десь увійти). У цьому випадку ви не хочете, щоб оболонка її видаляла.

Можливо, PATH може динамічно змінюватися, і тоді cat ви не вважаєте, що це так. Буде досить складно написати оболонку, виконуючи оптимізацію, про яку ви мрієте.

Також на практиці cat це досить швидка програма. Є кілька практичних причин (крім естетики), щоб цього уникати.

Дивіться також чудові розмови про розбір POSIX [s] від Ян Регіс-Джанаса на FOSDEM2018. Це дає інші вагомі причини, щоб не намагатися робити те, про що мрієте, у снаряді.

Якби продуктивність справді була проблемою для оболонок, хтось запропонував би оболонку, яка використовує складну оптимізацію компілятора програм, статичний аналіз вихідного коду та своєчасну техніку компіляції (всі ці три області мають десятирічний прогрес і наукові публікації та присвячені конференції, наприклад, під SIGPLAN ). На жаль, навіть як цікаву дослідницьку тему, яка наразі не фінансується науково-дослідними агенціями чи венчурними капіталістами, і я вважаю, що просто не варто докладати зусиль. Іншими словами, напевно, не існує значного ринку для оптимізації снарядів . Якщо у вас буде витрачено півмільйона євро на подібні дослідження, ви легко знайдете когось для цього, і я вважаю, що це дасть гідні результати.

З практичної сторони, переписування, щоб покращити його ефективність, зазвичай робиться невеликий (не сто рядків) сценарій оболонки на будь-якій кращій мові сценаріїв (Python, AWK, Guile, ...). І нерозумно (з багатьох причин інженерії програмного забезпечення) писати великі сценарії оболонки: коли ви пишете скрипт оболонки, що перевищує сто рядків, вам потрібно розглянути можливість його перезапису (навіть з міркувань читабельності та обслуговування) якоюсь більш підходящою мовою : як мова програмування оболонка дуже погана. Однак існує багато великих генерованих скриптів оболонок, і з поважних причин (наприклад, configureсценарії, створені GNU, автогенеровані ).

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


3
"Досить мало практичних причин, щоб цього уникнути" - той, хто чекав cat some-huge-log | tail -n 5бігу (де tail -n 5 some-huge-logміг стрибнути прямо до кінця, тоді як catчитає лише спереду), не погодився б.
Чарльз Даффі

Перевірка коментарів ^ catвеликого текстового файлу в десятках ГБ діапазону (який був створений для тестування) займає дещо довгий час. Не рекомендував би.
Сергій Колодяжний

1
BTW, re: "немає значного ринку оптимізації оболонок" - ksh93 - це оптимізуюча оболонка, причому досить непогана. Це було , на деякий час, успішно продається як комерційний продукт. (На жаль, отримавши комерційну ліцензію, це також зробило достатньо нішу, що погано написані клони та інші менш спроможні, але вільні від вартості спадкоємці заволоділи світом за межами тих сайтів, готових платити за ліцензію, що призводить до ситуації, що ми мають сьогодні).
Чарльз Даффі

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

2

Додавши до @Kusalananda відповідь (і коментар @alephzero), кішка може бути чим завгодно:

alias cat='gcc -c'
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

або

echo 'echo 1' > /usr/bin/cat
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Немає причин, що кішка (сама по собі) або / usr / bin / cat в системі насправді є котячим інструментом конкатенату.


3
Окрім поведінки cat, визначений POSIX, тому він не повинен різко відрізнятися.
roaima

2
@roaima: PATH=/home/Joshua/bin:$PATH cat ...Ви впевнені, що знаєте, що catзараз робить?
Джошуа

1
@Joshua це насправді не має значення. Ми обидва знаємо, що це catможе бути відмінено, але ми обидва знаємо, що це не повинно бути замінено чимось іншим. У моєму коментарі вказується, що POSIX передбачає певну (підмножину) поведінки, від якої можна чекати існування. Я часом писав сценарій оболонки, який розширює поведінку стандартної утиліти. У цьому випадку сценарій оболонки діяв і поводився так само, як інструмент, який він замінив, за винятком того, що він мав додаткові можливості.
roaima

@Joshua: На більшості платформ оболонки знають (або могли знати), які каталоги містять виконувані файли, що реалізують команди POSIX. Таким чином, ви можете просто відкласти заміну до моменту розширення псевдоніму та роздільної здатності, і робити це лише для /bin/cat. (І ви зробите це варіантом, який ви можете вимкнути.) Або зробите catвбудовану оболонку (яка, можливо, повертається до /bin/catдекількох аргументів?), Щоб користувачі могли контролювати, чи хочуть вони зовнішню версію звичайною чи ні шлях, с enable cat. Як і для kill. (Я думав, що баш command catспрацює, але це не пропускає вбудовані)
Пітер Кордес,

Якщо ви надасте псевдонім, оболонка буде знати, що catв цьому середовищі більше не відноситься до звичайного cat. Очевидно, оптимізація повинна бути здійснена після обробки псевдонімів. Я вважаю, що вбудовані оболонки представляють команди у віртуальному каталозі, який завжди є попереднім для вашого шляху. Якщо ви хочете уникнути вбудованої в оболонку версії будь-якої команди (наприклад test), вам слід скористатися варіантом із контуром.
Мікко Ранталайнен

1

Два "марних" використання для котів:

sort file.txt | cat header.txt - footer.txt | less

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

find . -name '*.info' -type f | sh -c 'xargs cat' | sort

... тут xargsможна прийняти практично нескінченну кількість імен і запустити catстільки разів, скільки потрібно, змушуючи все це вести себе як один потік. Отже, це працює для великих списків файлів, де прямого використання xargs sortнемає.


Обох цих випадків використання було б тривіально уникнути, зробивши вбудовану оболонку лише вхідним, якщо catвикликається точно одним аргументом. Особливо у випадку, коли shпередається рядок і xargsбуде дзвонити catбезпосередньо, немає можливості оболонці використовувати вбудовану реалізацію.
Мікко Ранталайнен

0

Крім інших речей, cat-визначення додасть додаткових накладних витрат та плутанини щодо того, яке використання catнасправді марно, IMHO, оскільки такі перевірки можуть бути неефективними та створювати проблеми з законним catвикористанням.

Коли команди мають справу зі стандартними потоками, вони повинні дбати лише про читання / запис до стандартних дескрипторів файлів. Команди можуть знати, чи можна шукати stdin / lseekable чи ні, що вказує на трубу чи файл.

Якщо ми додамо до суміші перевірку того, який процес насправді забезпечує вміст stdin, нам потрібно буде знайти процес з іншого боку труби та застосувати відповідну оптимізацію. Це можна зробити як з точки зору самої оболонки, як показано у публікації SuperUser від Кайла Джонса, так і з точки зору оболонки, яка

(find /proc -type l | xargs ls -l | fgrep 'pipe:[20043922]') 2>/dev/null

як показано у зв’язаній публікації. Це ще 3 команди (настільки додаткові fork()s і exec()s) та рекурсивні переходи (стільки всього readdir()дзвінків).

Що стосується вихідного коду C та оболонки, оболонка вже знає дочірній процес, тому рекурсії не потрібно, але як ми можемо знати, коли оптимізувати та коли catнасправді марно? Насправді корисні використання котів , такі як

# adding header and footer to file
( cmd; cat file; cmd ) | cmd
# tr command does not accept files as arguments
cat log1 log2 log3 | tr '[:upper:]' '[:lower:]'

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

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