Pull to refresh

Comments 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

Но если хочется сделать дырку в своей собственной системе... ну, вы всегда можете добавить "текущий каталог" в путь. Делов-то добавить в профиль PATH=,/:$PATH >

Вот правда потом такая шняга может сломать сборку gcc, например

Наблюдение первое

На самом деле в *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 кбайт, уже стоит подумать о пайпе

UFO just landed and posted this here

Как по мне, командная строка в 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.

Sign up to leave a comment.

Articles