Странная разница между pwd и / bin / pwd


15

Я добавил символическую ссылку в текущий каталог с ln -s . aa. Если я выполню cd aaи после этого выполню pwd, ответ будет /home/sim/aa.

Но если я выполню /bin/pwdего, то напечатает /home/sim(текущий каталог не изменился).

Откуда эта разница?

Ответы:


17

В большинстве оболочек, включая bash, pwdвстроена оболочка:

$ type -a pwd
pwd is a shell builtin
pwd is /bin/pwd

Если вы используете /bin/pwd, вы должны использовать -Lопцию, чтобы получить тот же результат, что и встроенный pwd:

$ ln -s . test
$ cd test && pwd
/home/cuonglm/test
$ /bin/pwd
/home/cuonglm
$ /bin/pwd -L
/home/cuonglm/test

По умолчанию /bin/pwdигнорирует символические ссылки и печатает актуальный каталог.

От info pwd:

`-L'
`--logical'
     If the contents of the environment variable `PWD' provide an
     absolute name of the current directory with no `.' or `..'
     components, but possibly with symbolic links, then output those
     contents.  Otherwise, fall back to default `-P' handling.

`-P'
`--physical'
     Print a fully resolved name for the current directory.  That is,
     all components of the printed name will be actual directory
     names--none will be symbolic links.

Встроенный pwdвключает символическую ссылку по умолчанию, за исключением того, что -Pиспользуется опция или -o physicalвстроенная установка set включена.

От man bash:

pwd [-LP]
              Print the absolute pathname of the  current  working  directory.
              The pathname printed contains no symbolic links if the -P option
              is supplied or the -o physical option to the set builtin command
              is  enabled.  If the -L option is used, the pathname printed may
              contain symbolic links.  The return status is 0 unless an  error
              occurs  while  reading  the  name of the current directory or an
              invalid option is supplied.

Я не уверен, что понимаю, откуда эти различия
user3581976

/bin/pwdпо умолчанию игнорирует символическую ссылку, прочитайте часть info pwdв моем ответе: Напечатайте полностью разрешенное имя для текущего каталога. То есть все компоненты напечатанного имени будут фактическими именами каталогов - ни один не будет символической
cuonglm

@ user3581976: см. мой обновленный для более ясного.
cuonglm

Почему есть команда -L для pwd, хотя она установлена ​​по умолчанию? И разве оболочка не использует команду / bin / pwd для запуска pwd?
user3581976

2
@ user3581976: Изображение, с которого вы запускаете оболочку set -o physical, теперь по умолчанию pwdявляется -Pопцией использования , если у вас нет -Lопции, как вы печатаете путь, содержащий символьную ссылку? Прочитайте это, https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.htmlчтобы узнать, что set -o physicalделает.
cuonglm

7

Для процесса возможно опросить файловую систему, чтобы определить ее текущий рабочий каталог, используя метод, который является слишком сложным, чтобы быть в теме в качестве ответа на этот вопрос. Это то, что делают pwdпрограмма и getcwdфункция библиотеки. На заре Unix они были единственными способами узнать, каков ваш рабочий каталог. Вот часть ответа на ваш вопрос, которую я не могу найти ни в одном из других ответов или даже где-либо еще на этом сайте (после 42-секундного поиска):

  • Когда оболочка запускается, она получает свой текущий рабочий каталог (возможно, путем вызова getcwd).
  • После этого, всякий раз , когда вы делаете cd, pushdили popd, оболочка отслеживает рабочий каталог с помощью функции манипулирования строк. Например,

    • Если ваш рабочий каталог /home/simи вы печатаете cd .., оболочка вычисляет, что ваш рабочий каталог /home.
    • Если ваш рабочий каталог /home/simи вы печатаете cd ., оболочка вычисляет, что ваш рабочий каталог все еще /home/sim.
    • Если ваш рабочий каталог /home/simи вы печатаете cd aa, оболочка вычисляет, что ваш рабочий каталог /home/sim/aa- без проверки, aaявляется ли символическая ссылка.

    Это позволяет сэкономить на стоимости звонков getcwd. Но это компромисс, поскольку он может привести к неверной информации.

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

Итак, суть в том, что оболочка может запутаться в том, где она находится. Но если вы набираете текст /bin/pwd, он запускается в отдельном процессе, который не имеет доступа к представлению оболочки о том, что такое рабочий каталог, и поэтому он определяет истинный рабочий каталог, по старинке. (Исключение: /bin/pwdпрограмма может посмотреть на переменную окружения PWD, и, очевидно, она это делает, когда вы указываете -L.) Вот еще один пример того, как оболочка может запутаться:

cd /home/sim/aa # Предположим , что /home, /home/simи/home/sim/aa
# все реальные каталоги (не символические ссылки).
pwd # Вывод: /home/sim/aaчто правильно.
mv ../aa ../bb
pwd # Вывод: /home/sim/aaчто неверно.
/bin/pwd # Вывод: /home/sim/bbчто правильно.


И, на всякий случай, если вам не ясно это, если вы печатаете ln -s . aaи cd aa, то ваш текущий рабочий каталог не изменился , больше, чем когда вы печатаете cd .- потому что, по сути, это то, что вы делаете, когда печатаете cd aa.


Спасибо, очень хороший ответ, это то, чего я ждал;)
user3581976

2
Этот ответ кажется немного согнутым . Это больше, -Lчем просто экономия затрат - и $PWDэто определяемая пользователем переменная среды, определяемая POSIX, - приложения пользовательского пространства, вероятно, должны доверять ей (что бы это ни значило ...?) . В любом случае, хотя я вовсе не фанат символических ссылок, это является прерогативой пользователя косвенно использовать столько сумасшедших указаний, сколько ему или ей следует выбирать с ними - и это то, что -Lважнее всего.
mikeserv

1
Это должен быть принятый ответ (символические ссылки не являются предметом вопроса).
Томас Дики
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.