Моя команда `which` может быть неправильной (иногда)?

17

Я скомпилировал последнюю версию emacs из исходного кода (v24.2), потому что версия, установленная на моем компьютере, (довольно) старая для меня (v21.3). Я сделал обычное:

$configure --prefix=$HOME
make 
make install

Сейчас я тестирую emacs и понял, что он все еще запускает предыдущую версию ... в то время как мой $HOME/binпуть должен переопределить системную (поскольку в моем .bashrcфайле он добавлен к $ PATH ).

Моей первой мыслью было увидеть whichвывод команды. И удивительно, это дает путь к новым Emacs. Я не могу понять, где здесь расхождение. В том же сеансе есть разные выводы:

$ emacs --version
GNU Emacs 21.3.1

$ `which emacs` --version
GNU Emacs 24.2.1

У меня нет псевдонима, связанного с Emacs. Совсем.

$ alias | grep emacs
$

Любая идея, что происходит, пожалуйста?

Ив Баумес
источник
что возвращает emacs?
Ульрих Дангел

Ответы:

29

Три возможности, которые приходят мне в голову:

  • Псевдоним существует для emacs(который вы проверили)
  • Функция существует для emacs
  • Новый emacsдвоичный файл отсутствует в хеш-таблице PATH вашей оболочки.

Вы можете проверить, есть ли у вас функция emacs:

bash-3.2$ declare -F | fgrep emacs
declare -f emacs

И удали это:

unset -f emacs

Ваша оболочка также имеет хеш-таблицу PATH, которая содержит ссылку на каждый двоичный файл в вашем PATH. Если вы добавляете новый двоичный файл с тем же именем, что и существующий в другом месте в вашем PATH, оболочка должна быть проинформирована путем обновления хеш-таблицы:

hash -r

Дополнительное объяснение:

which не знает о функциях, так как это не встроенный bash:

bash-3.2$ emacs() { echo 'no emacs for you'; }
bash-3.2$ emacs
no emacs for you
bash-3.2$ which emacs
/usr/bin/emacs
bash-3.2$ `which emacs` --version | head -1
GNU Emacs 22.1.1

Этот сценарий демонстрирует новое поведение двоичной хеш-таблицы.

bash-3.2$ PATH=$HOME/bin:$PATH
bash-3.2$ cd $HOME/bin

bash-3.2$ cat nofile
cat: nofile: No such file or directory
bash-3.2$ echo echo hi > cat
bash-3.2$ chmod +x cat
bash-3.2$ cat nofile
cat: nofile: No such file or directory

bash-3.2$ hash -r
bash-3.2$ cat nofile
hi
bash-3.2$ rm cat
bash-3.2$ cat nofile
bash: /Users/mrb/bin/cat: No such file or directory

bash-3.2$ hash -r
bash-3.2$ cat nofile
cat: nofile: No such file or directory

Хотя я этого не называл, which catвсегда возвращал первое catв моем PATH, потому что он не использует хеш-таблицу оболочки.

МРБ
источник
1
Хотя здесь есть хорошая информация, она упускает typeкоманду.
Иордания
Спасибо, у меня была та же проблема со свежекомпилированной версией sqlite3, которая сделала меня чокнутым (который действительно возвращал правильный путь, но оболочка не вызывала правильный sqlite3 cli). hash -rдействительно исправил мою проблему.
MPM
12

Да, не используйте который :

  • В некоторых системах это внешняя команда, реализованная в виде csh-скрипта, который может считывать конфигурацию, которая изменяет PATH.
  • Для этого есть встроенная функция. Два, даже: typeи command. POSIX способ:

    command -v emacs       # machine-readable format
    type emacs             # human-only format

    В bash вы также можете использовать type -p emacsтолько путь к внешней команде.

Однако и здесь, whichна самом деле, верно. Bash хранит информацию о местонахождении команды в памяти, чтобы в следующий раз она могла выполнить команду быстрее. Вы установили новый emacsисполняемый файл на свой компьютер PATH, но Bash все еще имеет старое расположение в своем кэше. Запустите, hash emacsчтобы emacsснова посмотреть или hash -rочистить кеш.

Жиль "ТАК - прекрати быть злым"
источник
1

Вы вышли из системы и вошли в систему, чтобы ваш обновленный .bashrcфайл логина был перечитан? Если нет, среда вашего текущего сеанса не была обновлена.

JRFerguson
источник
Если бы это было так, `which emacs` --versionсогласился бы emacs --version, потому что whichнаследует свой PATH от текущей оболочки.
mrb
@ mrb: Точка хорошо принята.
JRFerguson