Как удалить путь из переменной $PATH в fish?

Вопрос или проблема

Я использую 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 в репозиторий с этим примером. Я открыл задачу здесь.

короче говоря;

  1. echo $fish_user_paths | tr " " "\n" | nl // получите номер элемента, который хотите удалить, например, пятого
  2. set --erase --universal fish_user_paths[5] // удалите пятую папку универсально, чтобы она сохранялась в новых сессиях

Как говорит Элайджа, лучшая практика заключается в том, чтобы изменять fish_user_paths, а не глобальный PATH. Чтобы больше никогда не искать этот ответ в Google…

  1. Создайте несколько функций, которые только модифицируют fish_user_paths
  2. Сделайте обе функции автозагружаемыми

Чтобы добавить к пользовательским путям:

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
.....

Я надеюсь, что кто-то найдет это полезным, если кто-то знает, как сделать это лучше, то пожалуйста, дайте мне знать.

Старый вопрос, я знаю, но недавно он был актуализирован новым ответом. Вопрос и существующие ответы звучат для меня немного так:

Каждый раз, когда я встаю с постели, я режу ногу о разбитое стекло на полу рядом с кроватью. Что мне делать?

  1. Наклеить повязку на ногу каждый раз, когда я порежу ногу после того, как встану с постели?
  2. Или убрать разбитое стекло?

Мне не хочется быть таким педантичным, но мне кажется, что все существующие ответы (на протяжении многих лет) здесь в основном рекомендуют вариант “повязки”.

Вместо этого, разве не стоит сосредоточиться на исправлении коренной проблемы?!

В моей системе нет /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 при каждом запуске сеанса.

Вот шаги для удаления указанного пути:

  1. Показать текущие пути в fish_user_paths:

    Чтобы увидеть все текущие пути в переменной fish_user_paths, выполните следующую команду:

    echo $fish_user_paths

    Это даст вам список всех пользовательских путей.

  2. Определить индекс пути, который нужно удалить:

    Чтобы понять, какой индекс нужно удалить, вы можете преобразовать список в столбец и пронумеровать элементы:

    echo $fish_user_paths | tr " " "\n" | nl

    Обратите внимание на номер строки, соответствующий пути, который вы хотите удалить.

  3. Удалить путь по индексу:

    Предположим, что вы определили, что путь /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 может показаться неудобным, но благодаря её списковому виду и возможности создания функций, этот процесс можно значительно упростить. Убедитесь, что вы знаете, откуда берется проблемный путь, чтобы в дальнейшем избежать подобных ситуаций. Если у вас возникнут дополнительные вопросы, не стесняйтесь обращаться за помощью!

Оцените материал
Добавить комментарий

Капча загружается...