Комментарии 23
Будьте добры, поясните назначение ссылки с точкой. Мне в своё время знакомый линуксоид показал, что из терминала запустить программу можно вызвав её с припиской точки и слэша.
Вот так ругается:
$ krita-5.1.5-x86_64.appimage
krita-5.1.5-x86_64.appimage: command not found
А вот так запускается:
$ ./krita-5.1.5-x86_64.appimage
Использую как заклинание, но не понимаю в чем задумка.
В Linux поиск исполняемых файлов осуществляется по путям, прописанным в переменной окружения PATH. Текущий каталог в список этих путей не входит. Поэтому если Вам надо выполнить программу/сценарий из текущего каталога, следует явным образом указать к путь к исполняемому файлу, а не полагаться на умолчание. Это Вы и делаете через "точку".
Вот спасибо! Теперь понял. Баш ведь воспринимает команду как команду, типа "ls".
Возможно, Вам будет удобнее поместить программу в один из подкаталогов домашнего каталога пользователя, которые входят в список путей поиска PATH. Это может быть ~/bin или ~/.local/bin. Тогда можно будет запускать её без префикса. Как посмотреть список путей, прописанных в PATH, написано ниже. Пользовательские каталоги начинаются с "/home/имя_пользователя/...".
Дополню свой ответ практическим упражнением.
Чтобы посмотреть список путей в переменной PATH, можно выполнить команду:
$ echo $PATH
(обратите внимание, что пути разделяются двоеточием, а не точкой с запятой, как в Windows)
Вы можете временно (в текущем сеансе командной оболочки) добавить путь к текущему каталогу в переменную PATH так:
$ export PATH=$PATH:.
После этого запуск программы упростится:
$ krita-5.1.5-x86_64.appimage
Но добавлять текущий каталог в переменную PATH на постоянной основе не рекомендуется по соображениям безопасности.
Что не логично по сути своей.
Что мешает искать начиная с текущего и далее по прописанным в path?
А не вот этот костыль...
Так сделано для защиты от опечаток. "Злодей" может поместить в текущем каталоге исполняемый файл "ks". И тогда, если Вы промахнётесь по букве "l" в безобидной команде "ls", выполнится то, что выполняться не должно.
И в чём проблема "описки"? Описка одна на тысячу, а вводить каждый раз лишние символы, когда запускаешь программы из текущей директории.
Так сделано из-за косячного подхода изначального. И "линуксстайл" - пользователь должен страдать.
Есть ядро ОС Линукс (и иже с ним). Само по себе оно бессмысленное. Для любой ОС нужен набор базовых инструментов как то "операции над файловой системой", "редактирование/чтение файлов" и тп.
В линуксе это набор "утилит". Они базовые, без них смысла нет в операционке ибо ничего не сможешь сделать.
В чём проблема эти утилиты сделать вшитыми в командную оболочку? И не будет проблем с "описками" и "кто-нибудь плохой подсунул программу с тем же именем, что ls"(это вообще бред ибо в линуксе запуск по умолчанию несколько админскими правами у приложений и ограничение на лазанье в системные директории, т.е ничего страшного от запуска приложения не будет)... Лежит в директории файл с именем ls, запустил пользователь в ls в командной строке - так пусть и крикнет командная строка "чувак, у тебя коллизия с системной командой... Проверь что за фигня у тебя".
Dos и командная строка в винде вполне адекватно это отрабатывают.
Зы: ах да.. Зоопарк команд в линуксе. Что-то в программах висит, что-то в bash вшито как команда и пересечение имён норм живёт и bash адекватно кричит... А вводить ./ - бред. И хоть заминусите линуксойды, но это бред и костыль вводить лишний раз символы которые один фиг ты введёшь и заставишь выполнить что хочешь, но с оверхедом повводимым символам.
Как пользователь линукса полностью разделяю ваше негодование. Развели зоопарк, понимаешь. С другой стороны - ну если какая-то утилита так часто используется - может просто добавить ее в PATH?
Лежит в директории файл с именем ls, запустил пользователь в ls в командной строке - так пусть и крикнет командная строка "чувак, у тебя коллизия с системной командой... Проверь что за фигня у тебя".
находишься в такой директории (где чисто случайно есть файл "ls"), запускаешь скрипт, который запускает скрипт, который запускает скрипт, который запускает "ls". на каком уровне и какая должна произойти ошибка?
В какую из командных оболочек вы хотите вшить эти команды? Или во все сразу? А если человек не использует стандартный набор команд?
P. S. Как минимум zsh позволяет запустить команду без префикса ./
.
Кто тебе мешает добавить . в PATH и запускай себе сколько хочешь.
Причем можешь сам решать PATH=.:$PATH или PATH=$PATH:.
В том, чтобы не запускать файл из текущего каталога, есть глубокий сермяжный смысл. Заключается он в том, чтобы админ, бродящий по пользовательским каталогам, набрав ls, вызвал именно ту программу, которая список файлов показывает, а не малварь какую, которую хитрый юзер так назвал и в свой каталог положил.
Есть переменная $PATH
, которая содержит список путей, где искать файлы на исполнение. Например:
PATH=/bin:/usr/bin:/usr/local/bin
Когда в командой строке пишете что-то вроде:
$ какая-то-команда с какими-то ключами
то оболочка (bash, sh, zsh или, прости господи, cmd) ищет файл, перебирая все пути из переменной $PATH
. То есть оболочка ищет исполнимый файл, один из:
/bin/какая-то-команда
/usr/bin/какая-то-команда
/usr/local/bin/какая-то-команда
Как только будет найден файл для запуска (исполнения), поиск прекращается и вызывается команда с параметрами, например:
/какой/то/путь/какая-то-команда с какими-то ключами
Если вы явно описываете путь
./какая-то-команда с какими-то ключами
то поиск не производится, а делается попытка запустить такую команду.
Здесь описана упрощенная схема. Здесь не описаны особые случаи для псевдонимов (alias), функций, которые обрабатываются в первую очередь. Также не сказано про очень особый случай с cmd.exe
, который а) дополнительно смотрит на расширение файла (сравнивает с переменной %PATHEXT%
, ищет ассоциации по расширению, выполняет еще какие-то магические действия), б) игнорирует переменную %PATH%
, если в текущем каталоге имеется исполнимый файл с таким именем и в) некоторые его подводные камни.
Как минимум задумка в том, чтобы запуск программ (исполнимых файлов любого типа, которые вносят изменение в системе) был чётко регламентирован и подконтролен пользователю.
В системах подобных юникс есть право на исполнение. Как минимум - право владельца файла, группы и всех остальных. Даже без упоминания других возможностей, как исполнение от имени другого пользователя (суидность).
Большинство исполнимых файлов (с правом исполнения "для всех") размещены в конкретных местах. Опять волшебное понятие - регламент. Эти места описываются в переменной пути. Причём значение этой переменной может быть своё не только для конкретного пользователя, но вообще для каждой отдельной сессии, и даже для конкретной копии запущенного процесса от имени пользователя. Эта переменная - часть контекста.
Нет смысла хранить в этой переменно сотню мест, где могут быть исполнимые файлы. И не нужно искать исполнимые файлы каждый раз по всей файловой системе, которая может быть собрана в одно дерево из совершенно разных ресурсов...
Но главное - вообще не нужно запускать исполнимые файлы откуда попало. И вот тут главное - в системе может храниться несколько файлов с одним именем. Поэтому логично, безопасно и правильно запускать что-либо только из предназначенных для этого мест. Смотри переменную пути. И каждый исполнимы файл в безопасной системе должен быть с указанием владельца, группы и чётко определёнными правами права исполнения и изменения.
Это гарантирует, что что-то левое (и скорее всего зловредное) не проникнет в систему и даже с минимальными правами не наплодит в каждом доступном для изменения месте кучу исполнимых файлов, которые будут по имени совпадать с прочими программами, включая системные.
Именно поэтому для запуска чего-то нестандартного нужно указать полный путь. А полный путь к исполнимому фалу, который мы видим находясь в конкретной директории и есть точка-слеш - ./имя.исполнимого.файла.запустить_один.раз
И право исполнимости нужно устанавливать на файлы осознанно.
И разговор не только о разработчиках программ, у которых в процессе их деятельности может оказаться десяток различных версий под одним именем. Необходимость что-то выполнить может возникнуть у кого угодно.
Главное - это полный контроль пользователя за тем, что он запускает. И понимание, что он запускает, откуда и зачем. И ответственность за такой запуск лежит уже на пользователе. Вероятность обмана пользователя уменьшена на порядок...
Но если хочется сделать дырку в своей собственной системе... ну, вы всегда можете добавить "текущий каталог" в путь. Делов-то добавить в профиль PATH=,/:$PATH
Наблюдение первое
На самом деле в *nix системах правил разыменования намного больше, чем в cmd виндовом. И именно в этом вся соль, о которой вы написали, что оно происходит до выполнения команды.
В этом суть идеологии реализации команд, как кирпичиков, которые умеют делать что-то одно в явном виде. Банально конструкция for f in *; do smth; done. Все понятно и очевидно. Разыменование подставит имена найденных файлов по маске, а потом можно с ними делать всякое. В винде же банально научили команду dir неочевидной функции, и она перестала быть "простым" кирпичиком. В *nix я всегда знаю, что происходит не потому что это "фича" конкретной команды, а свойста языка оболочки
Упасть по памяти из-за большого числа файлов в каталоге - ну не знаю, интересно попробовать, а сколько это надо файлов создать?
Быстро попробовал, сделал 1000 файлов с длиной имени каждого 200+ символов. Ожидаемо ничего не упало.
Надо миллион? Ну такое, при таком размере сама команда ls будет тупить скорее всего, да и вообще любая операция с файлами в таком каталоге. Но ждать влом, пока миллион сделается
---------
Файлик кстати можно создать командой touch :)
Как по мне, командная строка в win - это просто какая-то заготовка, которую как-то слепили и выдали, чтобы было :)
Команда ls
по умолчанию сортирует результат своего выполнения. Вероятно, сортировка производится в памяти. Однажды я столкнулся с проблемой падения ls *
на нескольких десятках тысяч файлов. В таких случаях ls -U
или find
спасают ситуацию.
Упасть по памяти из-за большого числа файлов в каталоге - ну не знаю, интересно попробовать, а сколько это надо файлов создать?
Быстро попробовал, сделал 1000 файлов с длиной имени каждого 200+ символов. Ожидаемо ничего не упало.
Надо миллион? Ну такое, при таком размере сама команда ls будет тупить скорее всего, да и вообще любая операция с файлами в таком каталоге. Но ждать влом, пока миллион сделается
Насколько мне удалось выяснить, максимальная длина командной строки зависит от значения параметра ARG_MAX, установленного при сборке ядра Linux, и может быть получена командой:
$ getconf ARG_MAX
На доступной мне системе это значение - 2,097,152 (байта).
Давным давно ARG_MAX было в районе килобайта, потом очень долгое время 4 кбайта. Потом, с всеобщим внедрением UTF-8, меньше 32 кбайт уже вроде бы и нет.
Но в любом случае, если есть подозрение, что после всех expansions, длина командной строки будет больше 1-4 кбайт, уже стоит подумать о пайпе
Как по мне, командная строка в win - это просто какая-то заготовка, которую как-то слепили и выдали, чтобы было :)
Справедливости ради, COMMAND.COM (в Windows 9x) и CMD.EXE (в WinNT и его последователях до настоящего времени), видимо, связаны требованием совместимости с командным интерпретатором MS DOS. Возможности современной оболочки PowerShell гораздо шире. Но и для старых оболочек можно писать довольно сложные и полезные сценарии.
Честно говоря все проблемы слишком натянуты, а претензии к оболочке линукс идут только с точки зрения того, кто хочет чтобы было как в виндовс.
Шелл в линукс имеет свои способы решения, и их более чем достаточно.
То же обращение к файлу - нет такого как "все есть файл", это абстракция. Это может быть файл, директория, ссылка, жесткая ссылка, пайп, file special или device special, и это очень круто!
Генерирование списка файлов в командной строке имеет свой глубокий смысл.
Оболочка берет на себя работу с wildcard по генерации списка, что позволяет очень быстро и легко писать свои скрипты и утилиты для работы с этим списком.
Проблема длины командной строки давно решена благодаря утилите xargs.
Если же не хватает wildcard, есть find с богатым функционалом.
wildcard expansion и variable expansion это два мощнейших инструменты линукс шелла, и не нужно их сравнивать с cmd, который заменили на powershell и там совсем другая идеология.
$ sudo apt install moria.deb ... E: Unable to locate package moria.deb
Этот пример вообще неадекватный. Вы пытаетесь установить пакет не из файла, а из репозитория. Чтобы сказать что moria.deb это именно файл, нужно явно указать путь к файлу. Иначе будет выполняться поиск по репозиториям, а не в текущем каталоге.
Ну а наблюдение два я вообще не понял. Во всех операционных системах есть понятие абсолютного и относительного пути. И что самое важно, следует не забывать что работа с файловой системой это не столько особенность Линукс, сколько стандарт POSIX, который поддерживает и Unix и MacOs и Linux (и его производные типа Андроид), и другие, например WebOS.
Три наблюдения о командной строке и путях в файловой системе