
Вы нажимаете Enter: на экране вашего компьютера список всех файлов и каталогов в вашем текущем рабочем каталоге мгновенно осветляет ваше темное окно терминала, освещая вашу пыльную спальню и недоеденные пакеты с чипсами. Вы начинаете задумываться, почему в вашей файловой системе так много файлов с именем «bongo cat.c». Но вы также спрашиваете себя: «Как мой компьютер может мгновенно узнать все файлы, которые существуют внутри него, и представить их в удобном для чтения формате для меня, а я даже не могу перечислить все телешоу, которые я смотрели Netflix в прошлом году?» И ответ таков: вам, вероятно, не стоит тратить время на просмотр эксцентричных иностранных кулинарных шоу до трех часов ночи. Это, и в вашем компьютере есть то, чего нет у вас: система исполняемых программ внутри себя, которые используются для выполнения действий с умеренным или разумным успехом!
Основы
Ваш компьютер определенным образом интерпретирует команды, которые вы даете терминалу. Во-первых, важно понимать, что оболочка, которая запускает командную строку, обменивается данными с ядром, самой центральной основной программой в вашей системе, которая позволяет для запуска других программ, а также для общения с вашим оборудованием и управления ресурсами вашего компьютера. Когда вы вводите данные в командную строку, вы на самом деле отправляете информацию в оболочку, которая является просто еще одной программой, использующей функции и ресурсы, предлагаемые ядром.
Процесс
После ввода команды оболочка начинает с получения введенной команды в виде новой строки с помощью функции getline(). Эта функция указывает на стандартный ввод (stdin) и записывает введенную строку в адрес строки указателя символа (char *). Затем строка передается через функцию синтаксического анализа, называемую strtok(), которая преобразует строку в токенизированный массив аргументов с использованием пробела (" ") в качестве разделителя.

Путь
Следующий шаг включает в себя поиск по всем доступным папкам в PATH, чтобы найти первый аргумент, переданный в оболочку «ls». Чтобы получить доступ к пути, его сначала нужно найти в среде, которая существует в виде массива указателей символов (переменных среды), используемых системой для настройки своего поведения. В глобальной переменной environ можно получить доступ к $PATH, который является основным способом поиска исполняемых программ.
Переменная PATH среды использует формат ~PATH=usr/directory:usr/other/directory:usr/bin/3rddirectory , где разные каталоги, в которых выполняется поиск в PATH, разделены разделителем «:». Оболочка использует функцию getenv() для поиска PATH в среде и снова использует функцию токена для разделения различных путей, в которых может существовать команда.
Как только команда «ls» будет найдена в каталогах PATH, программа загружается в память и выполняется вызов fork(). Эта команда создает дочерний процесс на основе команды «ls», и поэтому оболочка помечается как родительский процесс. При этом и родительская, и дочерняя функции будут выполняться одновременно. Дочерний процесс будет иметь свой собственный идентификатор процесса (PID), связанный с ним, с PID родительского процесса, доступным внутри него, помеченным как PPID.
Далее происходит собственно суть процесса: выполнение программы! Чтобы продолжить, система оболочки вызывает основную функцию для выполнения программ: execve(). Эта функция принимает путь, в данном случае «/bin/ls», а также массив аргументов в виде массива указателей символов и выполняет его, используя массив указателей символов для среды, который передается в действовать как переменная окружения для вновь выполняемой программы. Это приводит к тому, что выполняемая в данный момент программа заменяется новой программой, которая только что была выполнена, с новой инициализированной кучей стека и сегментами данных.
После выполнения execve функция fork() возвращается дважды: как в родительской, так и в дочерней функциях. Возвращаемое значение Fork() зависит от того, находится ли он в дочернем или родительском процессе, поэтому его возвращаемое значение будет отрицательным, если создание дочернего процесса было неудачным, ноль, если функция возвращается к только что созданному дочернему процессу, или положительное число, если функция возвращается к исходному родителю или вызывающему процессу fork(). Это возвращаемое положительное число будет PID только что созданного дочернего процесса. Родительский процесс может выбрать остановку своих процессов с помощью функции wait(), которая приостанавливает выполнение до завершения дочернего процесса. Используя wait(), вы также можете получить статус завершения завершившегося дочернего процесса, если он понадобится процессу для продолжения работы.
Параметры
В инфраструктуре использования команд параметры используются для изменения работы команды различными способами, отображения новой информации или управления командой по-новому. Обычно они используются сразу после ввода команды, после чего следует «-», а затем используется любой доступный параметр в порядке его синтаксиса, который можно найти на странице руководства команды.
Без ввода параметра «-l» команда «ls» вернет список всех файлов в текущем рабочем каталоге:
usr@root:~/testing$ ls
example.c files.c lists.h main.c main.h tests
Как только вы включаете опцию «-l», список расширяется до формата длинного списка, который включает тип файла, права доступа к файлу, количество жестких ссылок на файл, владельца файла, группу файлов, размер файла, дату и время создание файла и имя файла. Его вывод будет выглядеть примерно так:
usr@root:~/testing$ ls -l
-rw — — — — 1 root files 27323 Jan 16 15:32 example.c
-rw-r — r — . 1 root files 18 May 20 2009 files.c
-rw-r — r — . 1 root files 176 May 20 2009 lists.h
и так далее. Таким образом, когда функция execve() находит опцию «-l», ее процесс изменяется, чтобы отразить операцию, которую использует «-l».
Подстановочные знаки
Подстановочные знаки — это символы или специальные символы, используемые оболочкой, которые представляют диапазоны других символов. К ним относятся звездочки (*), вопросительные знаки (?), и квадратные скобки ([]).
Звездочки обозначают совпадение одного или нескольких вхождений любого символа, включая отсутствие символа. Таким образом, *.c будет представлять любой файл, оканчивающийся на «.c», включая, возможно, файл с именем «.c». Вы также можете группировать файлы по их первому символу, поэтому m*.c будет представлять все файлы C, которые начинаются с «m».
Вопросительные знаки представляют собой вычисление одного вхождения любого символа, поэтому «?.c» будет представлять любой файл C, имя которого состоит только из одного символа (например, «a.c»). Обычно это используется для сбора всех файлов, используемых для компиляции функций C, поскольку они имеют только один символ в качестве типа файла («main.?» будет представлять файлы «main.c» и «main.h»).
Символы в квадратных скобках представляют собой любой символ или диапазон символов, заключенный в квадратные скобки. Таким образом, использование «[a:m]*.c» будет представлять все файлы C, которые начинаются с буквы от A до M.
Результат
Наконец, результат ввода «ls -l *.c», используя всю полученную информацию, будет отображать каждый файл C в текущем рабочем каталоге в формате длинного списка. Его выполнение будет выглядеть так:
usr@root:~/testing$ ls -l
-rw — — — — 1 root files 27323 Jan 16 15:32 example.c
-rw-r — r — . 1 root files 18 May 20 2009 files.c
-rw-r — r — . 1 root files 176 May 20 2009 main.c

Итак, мы только что выполнили нашу команду, и компьютер выдает нам ответ быстрее, чем мы когда-либо могли бы рассмотреть процессы выполнения команды сами. И теперь, когда мы точно знаем, как оболочка запускает свои процессы, у нас есть вся информация, которую скрывает от нас волшебный компьютерный ящик. Используйте его с осторожностью!