- Вопрос или проблема
- Системная конфигурация
- Конфигурация оболочки на уровне пользователя
- Универсальная переменная
- Параметры процесса родителя
- Ответ или решение
- Почему вы хотите удалить путь из $PATH?
- Как удалить путь из переменной $PATH в fish?
- Полезные функции для управления PATH
- Функция для добавления путей:
- Функция для удаления путей:
- Как исправить корневую проблему?
- Заключение
Вопрос или проблема
Я использую fish в качестве оболочки в Debian, и недавно (после некоторого обновления) всякий раз, когда я пытаюсь использовать автозавершение команд, я получаю:
set: Нет такого файла или каталога
set: Не удалось добавить компонент /usr/lib/x86_64-linux-gnu/libfm в PATH.
set: Нет такого файла или каталога
Запуск следующей команды:
echo $PATH
Выдает мне следующее:
/usr/lib/x86_64-linux-gnu/libfm /usr/local/bin /usr/bin /bin /usr/local/games /usr/games
В моей системе нет /usr/lib/x86_64-linux-gnu/libfm
, поэтому я понимаю, почему fish жалуется, но я не могу найти, как удалить этот путь из переменной $PATH
.
Кто-нибудь знает, как это сделать?
Способ настройки переменной $PATH в fish – это фактически использовать set --universal fish_user_paths $fish_user_paths /new/path/here
. Затем $fish_user_paths фактически добавляется в начало переменной $PATH при启动е новой сессии. Документация по $PATH в данный момент не говорит вам, как ее удалить.
В fish каждая переменная на самом деле является списком (массивом), и вы можете удобно получить доступ к каждому элементу напрямую, используя индекс. echo $fish_user_paths
выведет версию каждого элемента в списке с разделением пробелом, превратите пробелы в переводы строк с помощью функции перевода echo $fish_user_paths | tr " " "\n"
, а затем добавьте номера строк с помощью функции номерования строк echo $fish_user_paths | tr " " "\n" | nl
. Затем удалите его с помощью set --erase --universal fish_user_paths[5]
. Вы должны использовать --universal
, иначе это не сработает в новых сессиях.
Если у кого-то есть время, пожалуйста, отправьте PR в репозиторий с этим примером. Я открыл задачу здесь.
короче говоря;
echo $fish_user_paths | tr " " "\n" | nl
// получите номер элемента, который хотите удалить, например, пятогоset --erase --universal fish_user_paths[5]
// удалите пятую папку универсально, чтобы она сохранялась в новых сессиях
Как говорит Элайджа, лучшая практика заключается в том, чтобы изменять fish_user_paths
, а не глобальный PATH
. Чтобы больше никогда не искать этот ответ в Google…
- Создайте несколько функций, которые только модифицируют
fish_user_paths
- Сделайте обе функции автозагружаемыми
Чтобы добавить к пользовательским путям:
function addpaths
contains -- $argv $fish_user_paths
or set -U fish_user_paths $fish_user_paths $argv
echo "Обновленный PATH: $PATH"
end
Чтобы удалить пользовательский путь если он существует (частично кредит этому):
function removepath
if set -l index (contains -i $argv[1] $PATH)
set --erase --universal fish_user_paths[$index]
echo "Обновленный PATH: $PATH"
else
echo "$argv[1] не найден в PATH: $PATH"
end
end
И, конечно, чтобы сделать их автозагружаемыми:
funcsave addpaths; funcsave removepath
Пример использования:
> addpaths /etc /usr/libexec
Изменение PATH: /usr/local/bin /usr/bin /bin /usr/sbin /sbin
Обновленный PATH: /etc /usr/libexec /usr/local/bin /usr/bin /bin /usr/sbin /sbin
> removepath /usr/libexec
Изменение PATH: /etc /usr/libexec /usr/local/bin /usr/bin /bin /usr/sbin /sbin
Обновленный PATH: /etc /usr/local/bin /usr/bin /bin /usr/sbin /sbin
Это должно удалить пути с 6-го до последнего:
set -e PATH[6..-1]
Флаг -e – это удалить. Смотрите help set
.
Сбросьте fish_user_paths без пути, который не хотите больше:
$ set -U fish_user_paths /usr/local/bin /usr/bin /bin /usr/local/games /usr/game
Дополнительная информация: https://fishshell.com/docs/current/tutorial.html#tut_path
Я создал функцию fish, следуя ответу @Elijah Lynn, которая показывает добавленные пользователем пути и спрашивает, какие вы хотите удалить, и делает это.
Это мой первый скрипт на оболочке fish, поэтому, вероятно, он не очень хорош, но он выполняет свою задачу. Вот код:
function fish_remove_path --description "Показывает добавленные пользователем записи PATH и удаляет выбранную"
echo "Добавленные пользователем записи PATH"
set -l PATH_ENTRIES
echo $fish_user_paths | tr " " "\n" | nl
echo "Выберите номер записи для удаления, если больше одной, разделите значения пробелами"
read -d " " -a PATH_ENTRIES
for entry in $PATH_ENTRIES
if string match -qr '^[0-9]+$' $entry
# "$entry это номер!"
set -l FISH_ENTRIES (count $fish_user_paths)
if test $entry -gt $FISH_ENTRIES
echo "Индекс вне границ, должен быть между 1 и $FISH_ENTRIES" 1>&2
else
echo "Удаление $fish_user_paths[$entry]"
echo "Нажмите y для продолжения"
set -l confirmation
read confirmation
if test "$confirmation" = y
set --erase --universal fish_user_paths[$entry]
else
echo "пропускаю..."
end
end
else
echo "Предоставленный аргумент $entry не является числом" 1>&2
end
end
end
Чтобы использовать его, просто создайте файл с именем fish_remove_path.fish внутри ~/.config/fish/functions/. Затем, чтобы использовать его, просто введите fish_remove_path
.
Вот пример:
❯ fish_add_path /home/
❯ fish_remove_path
Добавленные пользователем записи PATH
1 /home
2 /opt/homebrew/bin
3 /opt/homebrew/anaconda3/bin/
Выберите номер записи для удаления, если больше одной, разделите значения пробелами
read> 1
Удаление /home
Нажмите y для продолжения
read> y
❯ echo $fish_user_paths
/opt/homebrew/bin /opt/homebrew/anaconda3/bin/
Вы можете дать ему более одной записи, скажем, вы хотите удалить записи 4, 5 и 6. Вам просто нужно ввести их, разделив пробелами:
❯ fish_remove_path
Добавленные пользователем записи PATH
1 /home
2 /opt/homebrew/bin
3 /opt/homebrew/anaconda3/bin/
4 /whatever1/
5 /whatever2/
6 /whatever3/
Выберите номер записи для удаления, если больше одной, разделите значения пробелами
read> 1 4 5 6
Удаление /home
Нажмите y для продолжения
read> y
Удаление /whatever1/
Нажмите y для продолжения
read> y
.....
Я надеюсь, что кто-то найдет это полезным, если кто-то знает, как сделать это лучше, то пожалуйста, дайте мне знать.
Старый вопрос, я знаю, но недавно он был актуализирован новым ответом. Вопрос и существующие ответы звучат для меня немного так:
Каждый раз, когда я встаю с постели, я режу ногу о разбитое стекло на полу рядом с кроватью. Что мне делать?
- Наклеить повязку на ногу каждый раз, когда я порежу ногу после того, как встану с постели?
- Или убрать разбитое стекло?
Мне не хочется быть таким педантичным, но мне кажется, что все существующие ответы (на протяжении многих лет) здесь в основном рекомендуют вариант “повязки”.
Вместо этого, разве не стоит сосредоточиться на исправлении коренной проблемы?!
В моей системе нет
/usr/lib/x86_64-linux-gnu/libfm
, так что я понимаю, почему fish жалуется, но я не могу найти, как удалить этот путь из переменной$PATH
.
В случае с этим вопросом, почему эта директория вообще ошибочно добавляется? Где она добавляется? Лучший способ (по-моему) удалить директорию из переменной $PATH
– это предотвратить ее добавление с самого начала (убрать разбитое стекло), а не пытаться исправить это позже.
Нахождение места, где это было добавлено, может потребовать небольшого отладки, но это не должно быть слишком сложно. Есть несколько мест, где я могу подумать о:
Системная конфигурация
после некоторого обновления
Указанный путь является частью файлового менеджера PCMan, но я не нашел никаких проблем относительно добавления его библиотеки в путь.
Тем не менее, если это было системное обновление, которое изменило это, то начните с проверки системного пути:
sudo -e /etc/environment
Если это не так, тогда проверьте, отображается ли директория в PATH
, когда вы работаете от имени root:
sudo -s
# Fish должна быть $SHELL, которая была выполнена, но если нет ...
fish
set --show PATH
Если плохая директория все еще присутствует, то, вероятно, это проблема конфигурации системы. Если нет, то это, вероятно, проблема конфигурации пользователя.
Для системы, конечно, проверьте, можете ли вы найти ссылку на плохой путь где-нибудь в /etc
:
sudo grep -r libfm /etc
Дополнительно, насколько я знаю, не должно быть никаких единиц Systemd, которые на это влияют. Systemd не имеет (на момент этого ответа) возможности устанавливать переменную окружения пользователя без довольно экстравагантных гимнастик (т.е. записи пользователей в JSON, которые еще не используются). Тем не менее, в какой-то момент может быть полезно проверить sudo grep -rs libfm /usr/lib/systemd
(флаг -s
подавляет сообщения о бинарных файлах, которые соответствуют).
Конфигурация оболочки на уровне пользователя
Если это конфигурация на уровне пользователя, тогда проверьте вашу пользовательскую конфигурацию, конечно. Я бы начал с:
grep -r libfm ~/.config ~/.local
Если необходимо, расширьте поиск:
grep -r libfm ~
Вы также можете заменить grep -r PATH ~
, чтобы посмотреть, есть ли строки, изменяющие PATH
. Возможно, директория libfm
может быть частью другой переменной, которая используется для изменения PATH
.
Универсальная переменная
Говоря о, всегда есть шанс, что она добавляется через $fish_user_paths
. Тем не менее, есть комментарий от автора вопроса в одном из удаленных ответов здесь, который указывает, что это не тот случай.
Но для других читателей, если это так, некоторые из вышеперечисленных ответов могут быть верными! Для проверки этого просто:
set --show fish_user_paths
Если плохая директория действительно там, тогда да, просто удалите ее на основе индекса (лучший пример в @ElijahLynn’s answer). Например, если $fish_user_paths[3]
является ошибочным путем, тогда:
set --erase --universal fish_user_paths[3]
В еще меньшем случае, что это какая-то другая переменная, которая установлена и используется для изменения PATH
:
set --show | grep libfm
Параметры процесса родителя
Наконец, есть шанс, что родительский процесс вашей оболочки изменяет окружение перед запуском Fish. Это было бы редкостью для такого типа проблемы, но это вполне возможно. pstree
и ищите любого общего родительского процесса вашей оболочки. Обычно это будет login
, init
(системы WSL), systemd
сам или что-то (не уверен, что это было бы на macOS).
Используйте ps -o ppid -p $fish_pid
, чтобы получить родительский процесс вашей оболочки, затем:
sudo -s
cat /proc/<pid>/environ
Есть ли ошибочный путь? Если да, то вам нужно выяснить, почему он устанавливается в том процессе (или одном из его родителей), чтобы удалить его.
Например, ваш echo $fish_user_paths
возвращает что-то вроде
/opt/homebrew/bin /foo/bar /aaa/bbb
И вы хотите удалить /foo/bar
. Вот как:
if set -l ind (contains -i -- /foo/bar $fish_user_paths)
set -e fish_user_paths[$ind]
end
Это решение разработчика Fish, Фабиана Бёма, также известного как foho. Прямая ссылка на его комментарий на GitHub: https://github.com/fish-shell/fish-shell/issues/2639#issuecomment-451260584
Решение простое, но это странно, что это не упоминается в документации.
Ответ или решение
Удаление пути из переменной окружения $PATH
в оболочке fish
может быть несколько непривычным, особенно если вы привыкли к другим оболочкам, таким как bash
или zsh
. Тем не менее, в fish
этот процесс упрощён благодаря уникальной системе работы с список переменных.
Почему вы хотите удалить путь из $PATH
?
Из вашего вопроса видно, что после недавнего обновления в системе, вы столкнулись с ошибкой, связанной с несуществующим каталогом /usr/lib/x86_64-linux-gnu/libfm
. Удаление этого пути из переменной $PATH
может помочь избежать подобных ошибок в будущем.
Как удалить путь из переменной $PATH
в fish
?
В оболочке fish
переменная $PATH
построена как список, который вы можете редактировать. Однако лучше всего работать с переменной fish_user_paths
, поскольку она автоматически добавляется в $PATH
при каждом запуске сеанса.
Вот шаги для удаления указанного пути:
-
Показать текущие пути в
fish_user_paths
:Чтобы увидеть все текущие пути в переменной
fish_user_paths
, выполните следующую команду:echo $fish_user_paths
Это даст вам список всех пользовательских путей.
-
Определить индекс пути, который нужно удалить:
Чтобы понять, какой индекс нужно удалить, вы можете преобразовать список в столбец и пронумеровать элементы:
echo $fish_user_paths | tr " " "\n" | nl
Обратите внимание на номер строки, соответствующий пути, который вы хотите удалить.
-
Удалить путь по индексу:
Предположим, что вы определили, что путь
/usr/lib/x86_64-linux-gnu/libfm
является, например, пятым элементом в списке. Для удаления этого пути выполните:set --erase --universal fish_user_paths[5]
Ключ
--universal
гарантирует, что изменения будут сохранены для будущих сеансов.
Полезные функции для управления PATH
Чтобы упростить процесс добавления и удаления путей в будущем, вы можете создать функции для выполнения этих операций автоматически.
Функция для добавления путей:
function addpaths
if not contains -- $argv $fish_user_paths
set -U fish_user_paths $fish_user_paths $argv
end
echo "Updated PATH: $PATH"
end
Функция для удаления путей:
function removepath
if set -l index (contains -i $argv[1] $fish_user_paths)
set --erase --universal fish_user_paths[$index]
echo "Updated PATH: $PATH"
else
echo "$argv[1] not found in PATH: $PATH"
end
end
Сохраните эти функции, чтобы сделать их доступными для всех сеансов:
funcsave addpaths
funcsave removepath
Как исправить корневую проблему?
Если вы хотите предотвратить добавление каталога /usr/lib/x86_64-linux-gnu/libfm
в будущем, вам нужно найти, где это изменение происходит. Проверьте ваши конфигурационные файлы на наличие упоминаний этого пути.
Некоторые места для проверки:
- Файлы конфигурации вашей оболочки, такие как
~/.config/fish/config.fish
. - Системные конфигурации, например
/etc/environment
. - Возможно, что какой-либо скрипт запускает вашу оболочку с этим параметром.
Если вы найдете, где этот путь добавляется, вы можете удалить или закомментировать соответствующую строку.
Заключение
Управление переменной $PATH
в fish
может показаться неудобным, но благодаря её списковому виду и возможности создания функций, этот процесс можно значительно упростить. Убедитесь, что вы знаете, откуда берется проблемный путь, чтобы в дальнейшем избежать подобных ситуаций. Если у вас возникнут дополнительные вопросы, не стесняйтесь обращаться за помощью!