Этот другой ответ хорош, но обсуждение в комментариях указывает, что более широкое объяснение может быть полезным.
Этот документ описывает, в какой последовательности POSIX-совместимая оболочка должна искать команды. Это очень общий, не самый простой способ понять. Вместо того, чтобы анализировать эту крайне абстрактную процедуру, давайте посмотрим, как действует реальная оболочка.
Если предположить,
- ваш
$PATH
выглядит так: /usr/local/bin:/usr/bin:/bin
;
- ты в Баш;
- вы вводите
ls
и нажимаете Enter ;
- псевдоним
ls
не изменил бы команду на что-то другое, кроме ls
;
тогда Bash запустит первый существующий объект ls
из списка ниже. Именно этот список с учетом вашего случая.
- функция
ls
.
ls
(обычно ls
не является встроенным в Bash; но поскольку Bash может динамически загружать новые встроенные команды, вы можете сделать ls
встроенным).
- Исполняемый файл
ls
с полным путевым именем, хранящимся в хеш-таблице (это произойдет, если когда-то в прошлом исполняемый файл ls
был найден в соответствии со следующим пунктом и все еще запоминается)
ls
исполняемого от $PATH
В вашем случае последовательность:
/usr/local/bin/ls
/usr/bin/ls
/bin/ls
Обратите внимание, что в процедуре нет ./ls
; ни в какой момент ваш текущий рабочий каталог не принимается во внимание, особенно если он не сопоставлен с записями в $PATH
.
Теперь это утверждение
Linux не просматривает текущий каталог, чтобы узнать, доступна ли конкретная команда из этого каталога
только означает, что в приведенном выше списке нет ./ls
в жестком коде . Он появится в списке, если ваш $PATH
содержится .
но
по соображениям безопасности текущий каталог не находится в $PATH
Я объясню эти причины позже в ответе. Тем не менее вы можете добавить .
на ваш $PATH
самостоятельно. В этом случае ./ls
появится в списке как запись 4.x. Сравните это с Windows, которая будет искать ls
в текущем рабочем каталоге независимо от того, находится он в $PATH
или нет. Если бы Linux делал то же самое, то всегда была бы запись ./ls
жестко закодированная где-то выше пункта 3 нашего списка.
Если текущим рабочим каталогом является /usr/bin
а в списке написано, что ls
должен разрешиться в /usr/bin/ls
, то технически он исполняется так же, как ./ls
- оболочка никогда не использует буквальный путь
./ls
, процедура выдает /usr/bin/ls
;
- тот факт, что вы находитесь в
/usr/bin
ничего не значит;
- тот факт, что
/usr/bin
находится в $PATH
очень много значит.
Но если бы вы имели .
в качестве первой записи в вашем $PATH
то
- оболочка будет использовать буквальный путь
./ls
;
- тот факт, что вы находитесь в
/usr/bin
будет много значить;
- тот факт, что
/usr/bin
находится в $PATH
, ничего бы не значил.
В обоих случаях это один и тот же исполняемый файл, который запускается в конце дня, но оболочка попадает к нему по-разному.
Стоит также отметить, что такие выражения, как «мой текущий рабочий каталог находится в моем $PATH
» или «я нахожусь в каталоге, который находится в моем $PATH
», не рассказывают всей истории. Они могут означать:
- «
/some/particular/directory
находится в моем каталоге $PATH
и в данный момент я нахожусь в /some/particular/directory
»
или же
Как показано, два случая различаются.
Похоже , что вы ожидали ls
не будет найдено только потому , что вы оказались в его каталоге. Ну, это было бы неудобно, в то время как не было бы никакого преимущества безопасности вообще. Основной причиной безопасности не имея .
как фиксированный шаг в общей последовательности поиска команд и за отсутствие .
в $PATH
описаны в этом FAQ по UNIX:
Рассмотрим, что происходит в случае, когда .
это первая запись в PATH
. Предположим, что ваш текущий каталог является общедоступным для записи, например, /tmp
. Если какая-то другая программа оставила там программу с именем /tmp/ls
и вы ls
(намереваясь, конечно, запустить обычную программу /bin/ls
), вместо этого будет запущена ваша оболочка ./ls
, программа другого пользователя. Излишне говорить, что результаты запуска неизвестной программы, как эта, могут вас удивить.
Нет смысла запрещать /usr/bin/ls
только потому, что вы находитесь в /usr/bin
. Если ls
там злонамеренный, вы, вероятно, уже запустили его, работая в другом каталоге, или в конце концов запустите его, работая в другом каталоге.
ТЛ; др
Подводя итог, можно сказать, что ls
в вашем примере работает, потому что найден /usr/bin/ls
, а не ./ls
. Тот факт, что последний путь переходит в первый, не имеет значения, потому что последний путь не используется в первую очередь. Он не используется, потому что «Linux не смотрит в текущий каталог…» (имеется в виду, что он не просматривается .
). Тем не менее он выглядит в /usr/bin
, потому что он находится в вашем $PATH
.