я установил
typeset -aU path
что помогает избежать дублирования в моем PATH. Дубликат не добавляется, если я добавляю его в конец моего PATH:
path+=~/bin
path+=~/foo
path+=~/bin
После этого мой PATH содержит только одну копию моего каталога bin.
Если я поставлю каталог в начало PATH (что делается редко, но иногда необходимо), т.е.
PATH=~/bin:$PATH
В конечном итоге у меня появится дополнительная копия моего каталога bin в моем PATH. Можно ли в этом случае также автоматически удалить дубликаты каталогов?
Я могу принудительно это сделать вручную с помощью вспомогательного массива, т.е.
temppath=($path)
path=($temppath)
но мне интересно, есть ли более простой способ сделать это.





Похоже, атрибут -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, это способ их очистить.
Опцию -U можно установить отдельно для PATH и path — я добавил в ответ несколько примеров вместе с другими примечаниями. Вероятно, нам не понадобится ~ в дополнении path=($^~path(/N)), но я не проверял каждый сценарий.
Я не думаю, что это правильно. Я установил -U только для path, и когда я обновляю path справа (конец массива), он становится уникальным, и это отражается в PATH, и наоборот. Использование зш 5.8.1
Что произойдет, если вы обновите его, используя PATH вместо path, и что показывают typeset -p PATH и typeset -p path? В документации zsh для -UPATH и path называются отдельными интерфейсами, что, возможно, является лучшим способом представления о них. Приведенные выше тесты проводились с zsh 5.9.
Действительно! Я проверил и смог проверить это и для своего zsh.
pathиPATH— связанные переменные. То, что вы делаете с одним, вы можете сделать и с другим. Я просто использую написание в зависимости от того, что мне удобнее печатать. Установка-Uдля обеих переменных не представляет никакой опасности, но не имеет никакого эффекта. Однако ваша идея избавиться от временного массива классная. Я не думал об этом. Не могли бы вы также объяснить синтаксис$^~path?~будет расширять тильду внутри переменной PATH (IMO ненужно), но как работает^? Я предполагаю, что это отвечает за удаление дубликатов.