Чому "ls" вимагає окремого процесу для виконання?


14

Чому lsдля його виконання потрібен окремий процес? Я знаю причину, чому такі команди, як cdне можна виконувати за допомогою механізму forking, але чи є шкода, якщо lsвони виконуються без розгортання?


1
Хоча lsце зовнішня програма, echo *або echo * .*(залежно від параметрів оболонки) виконує досить непогану роботу з перерахуванням файлів без розгортання.
Герріт

Це ще краще: printf "% s \ n" *
Коста

Примітка про різноманітність оболонки: tcsh має вбудований модуль, ls-Fякий діє ls -F. Це там для ефективності. Ви завжди отримуєте те, -Fщо зазвичай є хорошою ідеєю. Якщо ви вкажете будь-які інші параметри, він переходитиме до зовнішньої команди.

Відповіді:


18

Більш-менш відповідь ls- це зовнішній виконуваний файл. Ви можете побачити його місцезнаходження, запустивши type -p ls.

Чому тоді не lsвбудований в оболонку? Ну чому це має бути? Завдання оболонки - не охоплювати всі наявні команди, а забезпечувати середовище, здатне виконувати їх. Деякі сучасні оболонки мають echo, printfі їх називають вбудованими, які технічно не повинні бути вбудованими, але зроблені так з міркувань продуктивності, коли вони запускаються повторно (насамперед у щільних петлях). Не роблячи їх вбудованими, оболонка повинна буде розщедритися та виконати новий процес для кожного дзвінка до них, який може бути дуже повільним.

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

exec ls; echo "this never gets printed"

Оскільки зображення процесу вашої оболонки замінено, поточна оболонка більше не доступна після цього. Щоб оболонка могла продовжувати працювати після запуску ls, команда повинна бути вбудована в оболонку.

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


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

@llua я додав деяку інформацію про те , що і випадки виключення з echo, printfі так далі
Кріс Даун

Не завжди зрозуміло, чому одні речі є вбудованими, а інші - ні. Наприклад, чому це cdне зовнішній виконуваний файл?
Faheem Mitha

@FaheemMitha Там є зовнішній cdвиконуваний в POSIX-сумісних операційних систем ( дивіться тут ). Якщо ви хочете насправді chdir () в поточному процесі, вам потрібно, щоб він був вбудований в оболонку.
Кріс Даун

це стало звичкою, чому lsвона зовнішня, але вона може бути реалізована і в оболонці. Дивіться зайняту скриньку.

15

У Довідковому посібнику Баша зазначено:

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

Тобто, снаряди призначені для тільки включає вбудовані команди , якщо:

  1. Вимагається стандартом POSIX
  2. Команди, які потребують доступу до самої оболонки, такі як вбудовані контрольні завдання
  3. Команди, які дуже прості, не залежать від ОС і підвищують ефективність виконання, коли реалізуються як вбудовані модулі, такі як printf

lsКоманда не відповідає ні одному з перерахованих вище вимоги.

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

  1. Оболонка повинна бути окремою від файлової системи - ніякі вбудовані команди не повинні залежати від правильної роботи будь-якої файлової системи чи периферійних пристроїв
  2. Команда, яка може бути залежною від типу файлової системи або ОС, має бути окремим виконуваним файлом
  3. Команда, яку ви, можливо, захочете передати на або з неї, має бути окремим процесом
  4. Команда, яку ви можете запустити у фоновому режимі, має бути окремим виконуваним файлом
  5. Команду, яка має велику кількість можливих параметрів, краще реалізувати в окремому виконуваному файлі
  6. Команди, які повинні мати однаковий вихід, незалежно від того, який тип оболонки (bash, csh, tsh, ...) викликає їх, повинні бути автономними виконуваними файлами

Щодо першої причини - Ви хочете, щоб оболонка була максимально незалежною та стійкою. Ви не хочете, щоб оболонка застрягла на lsкріпленні NFS, який "не реагує на спроби"

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

Щодо третьої причини - для таких виразів, як find . -type d | xargs ls -ladце було б важко або неможливо здійснити lsв тому ж процесі, що і інтерпретатор оболонки.

Щодо четвертої причини - Деякі lsкоманди можуть зайняти тривалий час. Можливо, ви хочете, щоб оболонка тим часом продовжувала робити щось інше.


Примітка: Дивіться цей пост за Уоррен Янг у відповідь на подібне питання.


Ви пропустили простоту виводу труб, якщо це окрема команда, і все програмування, яке вона потребує, перетворить примітивні оболонки в окремий виконуваний файл.
Брюс Едігер

@BruceEdiger: Яке задоволення отримувати коментар від шанованої BE. Спасибі! Я вважаю, що причина 3 охоплює ваш коментар, ні?
Джонатан Бен-Аврахам

1
Я більше замислювався над тим, наскільки складним буде вихідний код самої оболонки, якби вона мала обробляти труби для зовнішніх процесів і переводити вихід внутрішньої команди, як гіпотетична, lsу зовнішній процес. Це можна було б зробити, але це було б складно.
Брюс Едігер

1
Боюся, більшість, якщо не всі ваші 5 балів суперечать. 1: ls (сподіваємось) не залежить від реалізації файлової системи. Це ядро, щоб забезпечити послідовний інтерфейс до стандартної бібліотеки та додатків. 2: ls, ймовірно, менше залежить від ОС, ніж оболонка. 3: оболонки, безумовно, дозволяють вбудовувати трубопроводи. 4: оболонки безумовно дозволяють запускати вбудовані тла у фоновому режимі. 5: це досить суб'єктивно.
jlliagre

1
@ JonathanBen-Avraham @BruceEdiger Чи не оболонки вже обробляють корпус труб для вбудованих з підкладками? наприклад bashвихід alias | grep ls. вхідcat /etc/passwd | while read a; do echo "$a"; done
Метт

2

lsне потребує окремого процесу. Дуже мало команд насправді вимагає окремого процесу: лише ті, яким потрібно змінити привілеї.

Як правило, оболонки реалізують команди як вбудовані лише тоді, коли ці команди потрібно реалізувати як вбудовані. Такі команди, якalias , cd, exit, export, jobs, ... потрібно прочитати або змінити деякий внутрішній стан оболонки, і , отже , не можуть бути окремі програми. Команди, які не мають таких вимог, можуть бути окремими командами; таким чином, їх можна викликати з будь-якої оболонки або іншої програми.

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

  • command- але він втратить свою корисність у ситуаціях, коли PATHможе бути не налаштовано належним чином, а сценарій використовується commandяк частина його налаштування.
  • echo - це вбудований для ефективності.
  • help - він може використовувати окрему базу даних, але вбудовування довідкового тексту у виконувану оболонку має перевагу зробити оболонку виконуваною самостійно.
  • kill - є дві переваги в наявності вбудованого модуля: він може розпізнавати позначення робочих місць на додаток до ідентифікаторів процесів, і його можна використовувати навіть тоді, коли не вистачає ресурсів для запуску окремого процесу.
  • printf- з тієї ж причини echo, що і для підтримки-v опції розміщення виводу в змінну.
  • pwd - вбудований пропонує додаткову можливість логічного відстеження поточного каталогу (залишаючи символьні посилання недоторканими, а не розширюючи їх).
  • test- це вбудований для ефективності (і bash також робить деякі магії з файлами, викликаними /dev/fd/…в деяких операційних системах).

Кілька оболонок пропонують значну кількість додаткових вбудованих конструкцій. Там в стулці , яка є оболонкою призначена для автономного довічних для аварійного ремонту (коли деякі зовнішні команди можуть не працювати). У ньому є вбудований ls, званий -ls, а також інші інструменти, такі як -grepі -tar. Вбудовані Sash мають менше можливостей, ніж повноцінні команди. Zsh пропонує деякі подібні вбудовані модулі zsh / files . Він не має ls, але розширення підстановки ( echo *) zstatможе виконувати подібну функцію.


2

Я думаю, що тут чогось не вистачає людям - це складна складність програми GNU lsв Linux. Порівнюючи виконуваний розмір lsдо bashі dashоболонок на моїй Debian, ми бачимо , що це досить великий:

graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30  2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls

Включення такої lsповноцінної, як версія GNU до bashзбільшить виконуваний розмір на 10%. Він майже такого ж розміру, як і повнийdash оболонка!

Більшість вбудованих оболонок вибрані тому, що вони інтегруються з оболонкою таким чином, що зовнішні виконувані файли не можуть (питання вказує cd, але іншим прикладом є bash версія killінтеграції з контролем роботи bash) або тому, що вони дуже прості команди для реалізації, що дає велику швидкість порівняно з розміром ( trueі falseнастільки ж просто, як це стає).

У GNU lsбув тривалий цикл розробки, і реалізація може запропонувати варіанти налаштування того, як / як відображаються результати. Використання вбудованого ls за замовчуванням може або втратити цю функціональність, або значно збільшить складність і розмір оболонки.


1

cdВбудована в оболонку, lsце окрема програма, яку ви побачите на /bin/ls.


0

Виконайте те, що шукаєте:

printf "%s\n" *

Також ви можете зберігати назви файлів у масиві:

files=(`printf "%s\n" *`)  #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done

Але це не стосується пробілів в іменах.
Це переходить до змінної і не хвилює пробілів:

printf "%s\n" * | while read a; do echo $a; done
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.