Очистка PATH в случае дубликатов

я установил

typeset -aU path

что помогает избежать дублирования в моем PATH. Дубликат не добавляется, если я добавляю его в конец моего PATH:

path+=~/bin
path+=~/foo
path+=~/bin

После этого мой PATH содержит только одну копию моего каталога bin.

Если я поставлю каталог в начало PATH (что делается редко, но иногда необходимо), т.е.

PATH=~/bin:$PATH

В конечном итоге у меня появится дополнительная копия моего каталога bin в моем PATH. Можно ли в этом случае также автоматически удалить дубликаты каталогов?

Я могу принудительно это сделать вручную с помощью вспомогательного массива, т.е.

temppath=($path)
path=($temppath)

но мне интересно, есть ли более простой способ сделать это.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, атрибут -U (уникальный) можно установить отдельно для каждой переменной в паре связанных параметров, таких как path и PATH. Два имени по существу действуют как отдельные интерфейсы для общего бита данных, и поведение меняется, когда для установки и получения этих данных используются разные интерфейсы.

Установив -U для path и PATH, оболочка должна удалять дубликаты независимо от того, как добавляются записи:

typeset -U PATH path

Это все, что абсолютно необходимо, поскольку по умолчанию атрибуты -T (связанный) и -a (массив) для path/PATH уже установлены. Для новой переменной, которая ведет себя аналогичным образом, объявление может выглядеть так:

typeset -aUT LD_LIBRARY_PATH ld_library_path

Тестирование:

=> typeset -aUT PATH path
=> PATH=/usr/bin
=> path+=~/bin
=> typeset -p path
typeset -aUT PATH path=( /usr/bin /Users/me/bin )
=> path+=~/foo
=> path+=~/bin
=> typeset -p path
typeset -aUT PATH path=( /usr/bin /Users/me/bin /Users/me/foo )
=> PATH=~/bin:$PATH
=> typeset -p path
typeset -aUT PATH path=( /Users/me/bin /usr/bin /Users/me/foo )
=> path=(~/foo $path)
=> typeset -p path
typeset -aUT PATH path=( /Users/me/foo /Users/me/bin /usr/bin )

Если -U установлено по-разному для PATH и path:

=> path=()
=> typeset -U path; typeset +U PATH
=> typeset -p PATH path
typeset -T PATH path=(  )
typeset -aUT PATH path=(  )
=> PATH=/foo:/foo:/foo
=> typeset -p PATH path
typeset -T PATH path=( /foo /foo /foo )
typeset -aUT PATH path=( /foo /foo /foo )
=> path+=/bar; path+=/bar; path+=/bar
=> typeset -p PATH path
typeset -T PATH path=( /foo /bar )
typeset -aUT PATH path=( /foo /bar )
=> PATH=/foo:$PATH; PATH=/foo:$PATH;
=> typeset -p PATH path
typeset -T PATH path=( /foo /foo /foo /bar )
typeset -aUT PATH path=( /foo /foo /foo /bar )

=> path=()
=> typeset +U path; typeset -U PATH
=> typeset -p PATH path
typeset -UT PATH path=(  )
typeset -aT PATH path=(  )
=> path+=/alice; path+=/alice; path+=/alice
=> typeset -p PATH path
typeset -UT PATH path=( /alice /alice /alice )
typeset -aT PATH path=( /alice /alice /alice )
=> PATH=$PATH:/bob; PATH=$PATH:/bob; PATH=$PATH:/bob; 
=> typeset -p PATH path
typeset -UT PATH path=( /alice /bob )
typeset -aT PATH path=( /alice /bob )

Бонус — path=($^~path(/N)) можно использовать для удаления несуществующих каталогов и недействительных записей из path:

=> typeset -p path   
typeset -aUT PATH path=( /Users/me/foo /Users/me/bin /etc/hosts /usr/bin )
=> path=($^~path(/N))
=> typeset -p path   
typeset -aUT PATH path=( /Users/me/bin /usr/bin )
  • ${^...} - эмулировать раскрытие скобок. Каждый элемент массива дополняется окружающим текстом, например: /Users/me/foo(/N) /Users/me/bin(/N) /etc/hosts(/N) /usr/bin(/N).
  • ${~...} - расширение глобуса. Полученные строки используются в качестве шаблонов glob.
  • (/) — включать в глобальные расширения только каталоги.
  • (N) — разрешить пустые результаты. Итак:
    /Users/me/foo(/N) расширяется до нуля/ноля, поскольку его не существует.
    /Users/me/bin(/N) становится /Users/me/bin.
    /etc/hosts(/N) имеет значение null, потому что это файл.
    /usr/bin(/N) становится /usr/bin.
  • path=(...) — сбрасывает path на все, что осталось от расширения. Если для -U установлено path, то добавляются только уникальные значения.

MacOS иногда добавляет бессмысленные записи через /etc/paths.d, это способ их очистить.

path и PATH — связанные переменные. То, что вы делаете с одним, вы можете сделать и с другим. Я просто использую написание в зависимости от того, что мне удобнее печатать. Установка -U для обеих переменных не представляет никакой опасности, но не имеет никакого эффекта. Однако ваша идея избавиться от временного массива классная. Я не думал об этом. Не могли бы вы также объяснить синтаксис $^~path? ~ будет расширять тильду внутри переменной PATH (IMO ненужно), но как работает ^? Я предполагаю, что это отвечает за удаление дубликатов.
user1934428 04.09.2024 12:20

Опцию -U можно установить отдельно для PATH и path — я добавил в ответ несколько примеров вместе с другими примечаниями. Вероятно, нам не понадобится ~ в дополнении path=($^~path(/N)), но я не проверял каждый сценарий.

Gairfowl 04.09.2024 20:30

Я не думаю, что это правильно. Я установил -U только для path, и когда я обновляю path справа (конец массива), он становится уникальным, и это отражается в PATH, и наоборот. Использование зш 5.8.1

user1934428 05.09.2024 11:48

Что произойдет, если вы обновите его, используя PATH вместо path, и что показывают typeset -p PATH и typeset -p path? В документации zsh для -UPATH и path называются отдельными интерфейсами, что, возможно, является лучшим способом представления о них. Приведенные выше тесты проводились с zsh 5.9.

Gairfowl 05.09.2024 13:00

Действительно! Я проверил и смог проверить это и для своего zsh.

user1934428 05.09.2024 13:57

Другие вопросы по теме