cdє вбудованою оболонкою оболонки POSIX :
Якщо проста команда призводить до імені команди та необов'язкового списку аргументів, слід виконати такі дії:
- Якщо ім'я команди не містить косої риски, повинен відбутися перший успішний крок у наступній послідовності:
...
- Якщо ім'я команди відповідає імені утиліти, зазначеному в наступній таблиці, ця утиліта буде викликана.
...
cd
...
- В іншому випадку команду слід шукати за допомогою PATH ...
Хоча це прямо не говорить про те, що він повинен бути вбудованим, специфікація продовжує говорити в описіcd :
Оскільки cd впливає на поточне середовище виконання оболонки, він завжди надається як регулярний вбудований оболонку.
З bashпосібника :
Наступні вбудовані команди оболонки успадковуються від оболонки Борна. Ці команди реалізуються, як визначено стандартом POSIX.
...
cd
cd [-L|[-P [-e]]] [directory]
Я гадаю, ви можете придумати архітектуру, де cdне повинно бути вбудованим. Однак ви повинні побачити, що означає вбудований модуль. Якщо ви пишете спеціальний код в оболонці, щоб зробити щось для якоїсь команди, ви наближаєтесь до вбудованого. Чим більше ви робите, тим краще просто мати вбудований.
Наприклад, у вас може бути оболонка, яка має IPC для зв'язку з підпроцесами, і там буде cdпрограма, яка перевірятиме наявність каталогу і чи є у вас дозвіл на доступ до нього, а потім спілкується з оболонкою, щоб сказати їй змінити її каталог. Однак вам доведеться перевірити, чи процес спілкування з вами є дитиною (або зробити спеціальні засоби спілкування лише з дітьми, наприклад, спеціальний дескриптор файлів, спільна пам'ять тощо), і чи процес насправді є запуск довіреної cdпрограми чи чогось іншого. Ось і ціла банка глистів.
Або у вас може бути cdпрограма, яка здійснює chdirсистемний виклик, і запускає нову оболонку зі всіма поточними змінними середовища, застосовані до нової оболонки, а потім вбиває її батьківську оболонку (якось), коли це завершено. 1
Гірше, що ви навіть можете мати систему, де процес може змінювати середовище інших процесів (я думаю, що технічно ви можете це зробити за допомогою налагоджувачів). Однак така система була б дуже, дуже вразливою.
Ви зможете додавати все більше коду для захисту таких методів, і значно простіше просто зробити його вбудованим.
Те, що щось є виконуваним, не заважає йому бути вбудованим. Справа в точці:
echo і test
echoі testє утилітами ( /bin/echoі /bin/test), призначеними POSIX . Але майже кожна популярна оболонка має вбудований echoі test. Аналогічно, killтакож вбудований модуль, який доступний як програма. До інших належать:
sleep (не так часто)
time
false
true
printf
Однак є деякі випадки, коли команда не може бути нічого, крім вбудованого. Одне з таких є cd. Як правило, якщо повний шлях не вказаний, а ім'я команди збігається з вбудованим, викликається функція, що відповідає цій команді. Залежно від оболонки, поведінка вбудованого та поведінки виконуваного файлу може відрізнятися (особливо це проблемаecho , яка має диво-різну поведінку . Якщо ви хочете бути певними щодо поведінки, бажано викликати виконуваний файл за допомогою повний шлях і встановити змінні типу POSIXLY_CORRECT(навіть тоді реальної гарантії немає).
Технічно нічого не заважає вам забезпечити ОС, яка також є оболонкою і має кожну команду як вбудований. Близьким до цього крайнього кінця є монолітний BusyBox . BusyBox - це єдиний двійковий файл, який (залежно від імені, з яким він називається) може вести себе як будь-яка з понад 240 програм , включаючи Almquist Shell ( ash). Якщо ви скасуєте PATHпід час роботи BusyBox ash, програми, доступні в BusyBox, все ще доступні для вас, не вказуючи a PATH. Вони наближаються до вбудованих оболонок, за винятком того, що сама оболонка є свого роду вбудованою в BusyBox.
Якщо ви подивитесь на dashджерело, потік виконання виглядає приблизно так (звичайно, за допомогою додаткових функцій, коли використовуються труби та інші речі):
main→ cmdloop→ evaltree→evalcommand
evalcommandпотім використовує findcommandдля визначення, що таке команда. Якщо це вбудований, то :
case CMDBUILTIN:
if (spclbltin > 0 || argc == 0) {
poplocalvars(1);
if (execcmd && argc > 1)
listsetvar(varlist.list, VEXPORT);
}
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
if (exception == EXERROR && spclbltin <= 0) {
FORCEINTON;
break;
cmdentry.u.cmdє struct( struct builtincmd), один з членів якої є покажчиком на функцію, з підписом типовою main: (int, char **). Ці evalbltinвиклики функцій ( в залежності від вбудованої , чи є evalкоманда чи ні) або evalcmd, або ця функція покажчик. Фактичні функції визначаються у різних вихідних файлах. echoНаприклад, це :
int
echocmd(int argc, char **argv)
{
int nonl;
nonl = *++argv ? equal(*argv, "-n") : 0;
argv += nonl;
do {
int c;
if (likely(*argv))
nonl += print_escape_str("%s", NULL, NULL, *argv++);
if (nonl > 0)
break;
c = *argv ? ' ' : '\n';
out1c(c);
} while (*argv);
return 0;
}
Усі посилання на вихідний код у цьому розділі базуються на номері рядка, тому вони можуть змінюватися без попереднього повідомлення.
1 POSIX-системи мають cdвиконуваний файл .
Бічна примітка:
У Unix та Linux є багато чудових публікацій, які стосуються поведінки оболонок. Зокрема:
Якщо ви ще не помітили схему в перелічених питаннях, майже всі вони стосуються Стефана Шазела .
typeкомандою