Почему мне нужно вводить `. /` Перед выполнением программы в текущем каталоге?

92

При выполнении программы на C a.out, используя терминал Ubuntu, почему мне всегда нужно печатать ./раньше a.out, а не просто писать a.out? Есть ли решение для этого?

Прашант Чихалкар
источник

Ответы:

119

Когда вы набираете имя программы, например, a.outсистема ищет файл в вашей переменной PATH. В моей системе PATH установлен на

/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

Ваш, вероятно, похож. Для проверки войдите echo $PATHв терминал.

Система просматривает эти каталоги в указанном порядке, и если она не может найти, программа выдает command not foundошибку.

Предварительно добавив команду к ./эффективному сообщению «забудьте о PATH, я хочу, чтобы вы смотрели только в текущем каталоге».

Точно так же вы можете указать системе искать только в другом определенном месте, добавив к команде относительный или абсолютный путь, такой как:

../означает в родительском каталоге, например, ../helloискать привет в родительском каталоге.

./Debug/hello: "ищите helloв подкаталоге Debug моего текущего каталога."

или /bin/ls: "искать lsв каталоге /bin"

По умолчанию текущий каталог не находится в пути, поскольку считается угрозой безопасности. Посмотрите, почему. не в пути по умолчанию? на суперпользователя почему.

Можно добавить текущий каталог в вашу переменную PATH, но по причинам, указанным в связанном вопросе, я бы не рекомендовал это делать.

Уоррен Хилл
источник
25
Этот. +1 Не добавляйте .к себе PATH(как предлагают другие 2 ответа) из-за угрозы безопасности, упомянутой в этом ответе.
День
8
Также стоит отметить, что здесь нет ничего особенного ., вы можете использовать полный или относительный путь к исполняемому файлу, например, /home/user/foo/a.outили./build/a.out
tobyodavies
@tobyodavies; На самом деле .он особенный, потому что он означает «мой текущий каталог», поэтому он может быть любым каталогом, в котором пользователь находит себя с привилегиями чтения и выполнения. Это потенциально более опасно, чем добавление определенного полного пути.
Уоррен Хилл
@WarrenHill, если подумать о добавлении его в свой путь, да, это совсем другое. Тем не менее, с точки зрения синтаксиса bash, он .не имеет особого статуса, это просто путь, с которого можно начинать, /и он ./blahбудет работать так же хорошо с catили grepкак приглашение bash.
tobyodavies
@tobyodavies: Хорошо, я отредактировал свой ответ, чтобы включить вашу точку зрения.
Уоррен Хилл
24

Причина этого проста.

Предположим, у вас есть команда с тем же именем, что и приложение в текущем каталоге. Затем выполнение команды в оболочке вызовет ваше приложение вместо встроенной команды. Это было бы проблемой безопасности, если ничего больше.

Требуя ./использования спереди, оболочка знает, что вы хотите выполнить приложение с заданным именем, а не встроенную команду с этим именем.

Натан Осман
источник
1
Ваше объяснение вводит в заблуждение, есть разница между встроенными в оболочку командами и исполняемыми файлами, доступными через переменную PATH. На самом деле ваш ответ, чем больше я читаю, тем более некорректен.
Ахмед Масуд
16

./выполняет файлы, которых нет в вашем $PATH, скорее он выполняет файл в текущем каталоге (или другом через ./home/stefano/script.sh). Теперь PATH - это переменная окружения, которая содержит все места, где bash может искать исполняемые программы, не имея полного (абсолютного) пути к ним.

Это разделение необходимо, чтобы избежать запуска неправильного файла. То есть, если у вас есть файл, который называется lsв вашем домашнем каталоге, он не будет находиться в вашей переменной PATH, чтобы bash не перепутал его с реальным ls. Переменная PATH также определяет порядок поиска:

  • Когда вы запускаете команду или программа пытается выполнить execсистемный вызов (особый метод ядра, способ запуска программ), система ищет файл, просматривая каждый из каталогов в вашей переменной PATH. Как только программа найдена, даже если она находится в нескольких каталогах, поиск прерывается, и запускается первая найденная программа.

Чтобы запустить файл, вам нужно установить исполняемый бит в разрешениях:

  • Поскольку вы уже в командной строке, вы можете просто набрать chmod +x finename.

  • Или вы можете установить разрешения, щелкнув правой кнопкой мыши файл и выбрав Свойства :

    альтернативный текст

Теперь вы можете скопировать файл в любой из каталогов в PATH, чтобы увидеть, какие из них там - и они установлены для каждого пользователя - типа echo $PATH.

stefano@3000-G530:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

Если вы создаете исполняемый файл catи перемещаете его в него /usr/local/sbin, он запускается вместо правильного cat, который находится в /bin. Вы можете узнать, где находятся ваши файлы, используя type catи whereis cat.

Стефано Палаццо
источник
2
Стоит отметить одну вещь: его вопрос, кажется, указывает на то, что он скомпилировал и связал что-то gcc, что автоматически устанавливает бит выполнения.
Натан Осман
12

Зачем вам нужно печатать ./перед выполнением программы?

В терминале всякий раз, когда вы вводите имя приложения, скажем gedit, терминал будет искать в некоторых (предопределенных) каталогах, которые содержат приложения (двоичные файлы приложений). Имена этих каталогов содержатся в переменной с именем PATH. Вы можете увидеть, что находится в этой переменной, выполнив echo $PATH. Видите эти каталоги, разделенные :? Те каталоги , что терминал будет идти поиск, если вы просто ввести gedit, nautilusили a.out. Как видите, пути вашей a.outпрограммы там нет. Когда вы это делаете ./a.out, вы говорите терминалу: «Посмотрите в текущем каталоге и запустите a.out, а не заходите PATH.

Решение 1

Если вы не хотите печатать ./каждый раз, вам нужно добавить a.outкаталог в $PATH. В следующих инструкциях я предполагаю, что путь к a.outявляется /path/to/programs/, но вы должны изменить его на свой фактический путь.

  1. Просто добавьте следующую строку в конец файла ~/.pam_environment:

    PATH DEFAULT=${PATH}:/path/to/programs

    Источник: постоянные переменные среды

  2. Выйдите из системы и снова войдите в нее. Теперь вы сможете работать a.outбез ./каких-либо каталогов.

Если у вас есть другие программы в других каталогах, вы можете просто добавить их в строку выше. Однако я бы посоветовал иметь, например, один каталог с именем «myPrograms» и поместить все свои программы в него.

Решение 2

Примечание: измените userNameсвое фактическое имя пользователя Ubuntu.

Что если у вас есть другие программы, которые вы хотите запустить? И они все в разных папках? Что ж, «более организованным» решением было бы создать папку с именем binв вашем домашнем каталоге и добавить символические ссылки (ярлыки) в эту папку. Вот как:

  1. mkdir /home/userName/bin

    • Это создаст папку binв вашем домашнем каталоге.
  2. ln -s /path/to/programs/a.out /home/userName/bin

    • Это создаст «символическую ссылку» (в основном, ярлык) вашей a.outпрограммы под bin.
  3. Выйдите из системы и снова войдите в нее. Теперь вы сможете работать a.outбез ./каких-либо каталогов.

Теперь, когда у вас есть другая программа где - нибудь еще, скажем , программу b.inна вашем рабочем столе, все , что вам нужно сделать , это: ln -s /home/userName/Desktop/b.in /home/userName/binи тогда вы будете иметь возможность запускать его без , ./а также.

Примечание: благодаря комментарию @ Джо , когда вы делаете резервные копии, символические ссылки должны обрабатываться специально. По умолчанию они rsyncвообще не обрабатываются, поэтому при восстановлении их там нет.

Алаа али
источник
1
Это удобный трюк, если он используется экономно. Его частое использование заставляет вашу систему делать то, чего никто не ожидал. Кроме того, когда вы делаете резервные копии, символические ссылки должны обрабатываться специально. По умолчанию rsync их вообще не обрабатывает, поэтому при восстановлении их там нет.
Джо
1

Как указал Джордж в своем ответе, это поможет вам заметить, что вы выполняете файл в текущем рабочем каталоге ( pwd).

Я не забываю задавать этот вопрос своему старшему давным-давно, он сказал, что я должен добавить .к своему пути, чтобы, когда я делаю, a.outон смотрел в текущем каталоге и выполнял это. В этом случае мне не нужно делать ./a.out.

Но лично я бы рекомендовал против этого. Это никогда не случалось со мной, но если вы находитесь в инопланетном сетевом каталоге или чем-то подобном, и там существует вредоносный исполняемый файл с именем ls, то иметь .на своем пути - очень плохая идея. Не то чтобы вы сталкивались с этой проблемой очень часто, просто говоря.

Шрикант Шарат
источник
хорошо, Стефано принял свой ответ, чтобы содержать эту информацию :)
Shrikant Sharat
3
Я полностью согласен с тем, чтобы не добавлять .в $PATH. Очень опасная идея.
Натан Осман
1

В дополнение к другим ответам, вот основная часть, из man bashкоторой хорошо это объясняется:

КОМАНДНОЕ ИСПОЛНЕНИЕ
       После того, как команда была разбита на слова, если это приводит к простому
       команда и необязательный список аргументов, следующие действия
       приняты.

       Если имя команды не содержит косых черт, оболочка пытается найти
       Это. Если существует функция оболочки с таким именем, эта функция
       вызывается, как описано выше в FUNCTIONS. Если имя не соответствует
       функция, оболочка ищет его в списке встроенных функций оболочки. Если
       найдено совпадение, которое встроено.

       Если имя не является ни функцией оболочки, ни встроенным, и не содержит
       косая черта, bash ищет каждый элемент PATH для поиска
       присвоение исполняемого файла по этому имени.
mook765
источник
0

«./» имеет смысл, когда вы запускаете программу, которая вам известна и конкретна, например, ваша собственная. Эта программа должна присутствовать в вашем текущем каталоге. «./» не имеет смысла, когда вы запускаете стандартную команду, которая находится где-то в $ PATH. Команда «какая команда запускается» сообщает вам, где находится команда запуска в $ PATH.

user7346
источник
0
$ gcc hello.c -o /path/to/someplace/hello

создаст исполняемый файл в каком-то месте. Если это место находится на вашем пути, вы сможете запустить файл. Вы можете написать это, если хотите создать метку для действия «скомпилируйте этот исходный код, используя gcc, и поместите исполняемый файл в какое-то место на вашем пути»

Я бы посоветовал вам создать новый каталог с именем «testbin» или что-то в этом роде и поместить его в свой путь, чтобы сохранить существующие каталоги путей чистыми.

Джон Кипарски
источник
0

./устраняет ненужный поиск пути. ./заставить искать только в текущем каталоге. Если мы не дадим, ./он будет искать различные пути, заданные в системе, например /usr/bin, /usr/sbin/и т. Д.

user175959
источник
0

«./» означает, что вы хотите выполнить файл в текущем каталоге, это ярлык для ввода полного пути, например:

[root@server ~]#/path/to/file/file.pl

такой же как:

[root@server file]#./file.pl

в предыдущем примере вы прошли каталог и его вспомогательные каталоги к расположению файла и использовали «./» для запуска файла в текущем каталоге.

тот, что перед ним, « [root @ server ~] # / path / to / file / file.pl » также выполнит файл, если вам лень «cd» пробраться к папке с файлом.

Халед Мустафа
источник
-4

Это очень просто и имеет много применений.

  1. Если установлено несколько версий одного и того же приложения, оно будет доступно по другому пути, но в нем можно создать мягкую ссылку на ваш двоичный файл /usr/bin. Например, Python 2.7, Python 2.6 установлен, но / usr / bin / python -> python2.7 / usr / local / bin / python -> python2.6

Если вы находитесь в пути /usr/local/binи выполняете Python, он всегда будет выполнять Python 2.7. Указание .займет исполняемый файл текущей папки.

  1. .- всегда представляет выполнение из текущего каталога. И ..всегда означает, что выполняется из предыдущего каталога.
Рамджи Анна
источник