Fish-shell: PATH/MANPATH/CDPATH в специальном регистре выглядит странно; нам нужно более общее решение, такое как "привязанные" переменные zsh

Созданный на 11 дек. 2012  ·  52Комментарии  ·  Источник: fish-shell/fish-shell

В expand.h :

/** Character for separating two array elements. We use 30, i.e. the ascii record separator since that seems logical. */
#define ARRAY_SEP 0x1e

/** String containing the character for separating two array elements */
#define ARRAY_SEP_STR L"\x1e"

Это приводит к:

xiaq<strong i="10">@blackie</strong> ~> set a (printf 'a\x1eb')
xiaq<strong i="11">@blackie</strong> ~> count $a
2
xiaq<strong i="12">@blackie</strong> ~> set a (printf 'a\x1fb')
xiaq<strong i="13">@blackie</strong> ~> count $a
1

Понятно, что char \x1e рассматривается как разделитель элементов.

enhancement

Все 52 Комментарий

Обеспокоенность тем, что нет способа представить \x1e? Или вы думаете об архитектурных улучшениях?

Я думаю, что разделитель массивов в основном используется в сохраняемых массивах в местах, которые принимают только строки, такие как универсальные переменные или переменные среды.

在 2012-12-12 上午2:09,"ridiculousfish" уведомления@github.com写道

Обеспокоенность тем, что нет способа представить \x1e? Или ты думаешь
об архитектурных улучшениях?

Я бы сказал, что имею в виду обе проблемы. Для первого просто подумайте о
имя файла со встроенным \x1e. POSIX говорит, что разрешено все, кроме \0.
имена файлов, так что это вполне возможно. Использование \0 в качестве разделителей массива может быть
немного лучший выбор, но это приводит ко второй проблеме - это
хрупкий и явно неправильный.

Я думаю, что разделитель массивов в основном используется для сохранения массивов в местах
которые принимают только строки, такие как универсальные переменные или переменные среды.

Если сохранение означает «сериализованный», нет. Массивы всегда хранятся в
\x1e-форма с разделителями. Экспортированные массивы среды соединяются знаком «:». Они
хотя используются в универсальных переменных - что ИМХО должно быть реализовано
с правильным побегом вместо этого.


Ответьте на это письмо напрямую или просмотрите его на GitHub.

Как насчет использования символа области частного использования в качестве разделителя? Фиш уже использует некоторые из них в некоторых случаях.

@JanKanis Это не лучше; это вполне возможно в именах файлов (учитывая файловые системы, использующие не-utf8, собственные кодировки) и других строках.

Я бы сказал, что среди прочего, "\0" является _немного_ лучшим выбором среди других, так как это единственный символ, который UNIX запрещает в именах файлов, но он все еще имеет для меня неприятный запах. Кроме того, мы уже много разбираем и собираем массивы, и я ожидаю, что реализация настоящих массивов приведет как к лучшей архитектуре, так и к меньшему количеству кода.

Fish уже обрабатывает символы частного использования и недопустимые байты, когда он кодирует внешние строки в wchars. Эти специальные значения кодируются байт за байтом в определенный набор символов частного использования, которые fish также снова декодирует на выходе, поэтому, в принципе, использование другого символа частного использования может работать. Однако я согласен, что использование истинных массивов намного лучше. Есть одна сложность в том, что связь между fish и fishd происходит через сокет с использованием строк utf8, и там fish использует (я думаю) управляющую последовательность "\x1e" (а не байт 0x1e) для разделения элементов массива. Но это, вероятно, можно решить, используя, например, частную неиспользуемую управляющую последовательность.

Я разделяю опасения xiaq, но (для практических целей) я нахожу неявное разделение на \n более оскорбительным:

a<strong i="6">@raspeball</strong> ~> count (printf 'a\x1eb')
1
a<strong i="7">@raspeball</strong> ~> count (printf 'a\nb')
2

Интерпретация массива (с разделителями строк) вывода подпроцесса должна быть явной и необязательной!

Но это, вероятно, не имеет ничего общего с базовым хранилищем массивов…

@xiaq : Что не так с использованием \0 ? xargs , похоже, использует его как «надежный» вариант.

Вы не можете использовать \0 в переменных среды, поэтому будет сложно экспортировать массивы в дочерние оболочки.

Я перехожу с zsh, где я использую эту последовательность для определения $LESS env var разумным образом, используя его функцию «связанных» переменных:

typeset -xT LESS less ' '
less=(
    --HILITE-UNREAD
    --LONG-PROMPT
)

Я опустил полный список опций для краткости. В zsh это приводит к тому, что $LESS env var представляет собой список параметров, разделенных пробелами, в массиве $less. Эквивалент в fish приводит к тому, что элементы разделяются символом разделителя записей (\x1e). Несмотря на то, что в документации говорится, что элементы массива будут разделены пробелами (по модулю специальных массивов, таких как PATH). Я должен явно выполнить присваивание, которое интерполирует значения в одну строку, чтобы получить ожидаемый результат:

set -x LESS --HILITE-UNREAD \
    --LONG-PROMPT
set LESS "$LESS"

На данный момент мне все равно, используется ли \x1e внутри для сериализации массивов, а не \x00. Меня волнует, что элементы экспортируемых массивов разделены символом \x1e. Это просто сломано, неправильно, фубар. Подбери свое прилагательное. Это также несовместимо с вышеупомянутым обходным путем и задокументированным поведением. Эта проблема должна быть помечена как ошибка ИМХО.

PS. Нигде в документации не упоминается использование символа разделителя записей (\x1e). Что является еще одной проблемой.

@ krader1961 Спасибо, что поделились этим. Не существует стандартного соглашения Unix для переменных окружения, подобных спискам — некоторые из них разделены двоеточием, другие — пробелом. fish использует \x1e, чтобы различать свои собственные массивы.

Не могли бы вы указать нам на ошибочную документацию?

Как вы думаете, как экспортируются массивы - двоеточия, пробелы, новые строки, что-то еще? Должна ли рыба токенизировать переменные окружения и для этого персонажа?

Похоже, что less ожидает аргументы, разделенные пробелами. Вероятно, самый простой обходной путь — это set -x LESS '--HILITE-UNREAD --LONG-PROMPT' и т. д.

Стандарта для списков, подобных переменным среды, не существует, потому что по определению они представляют собой произвольную последовательность байтов, состоящую из ключа и значения, разделенных знаком равенства и заканчивающихся нулевым байтом. Они даже не должны быть печатными символами. Единственным общепринятым соглашением для более высокого уровня абстракции является соглашение, установленное функцией execlp() для PATH env var.

Документация ошибочна, поскольку в ней не упоминается использование \x1E, \036, 30 или символа «разделителя записей» для разделения элементов массива при экспорте переменной с более чем одним элементом. В документации указано, что

..., and array variables will be concatenated using the space character.

Это из раздела «Расширение переменных» в http://fishshell.com/docs/current/index.html. Разумно предположить, что это утверждение также применимо к экспортируемым переменным, которые не имеют специального регистра, как описано в разделах «Массивы» и «Специальные переменные» того же документа.

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

При отсутствии механизма для настройки символа, который будет использоваться на основе var by var (аналогично команде zsh "typeset -T"), при объединении элементов массива следует использовать пробел (опять же, исключая разделенные двоеточием специальные регистры vars). ). Очевидно, это не относится к частным хранилищам данных, таким как хранилище универсальных переменных.

Наконец, я не смог найти никакого применения в стандартных функциях fish, где env var используется для передачи массива, содержащего более одного элемента, в другую функцию или скрипт. Такие варианты использования могут существовать, но они должны требовать, чтобы сценарии явно взаимодействовали при сериализации/десериализации данных, а не полагаться на fish для неявного восстановления массивов из переменных, строки которых содержат символ разделителя записей.

Спасибо за ваш вдумчивый ответ. Раздел, который вы цитируете о конкатенации с использованием пробела, предназначен специально для строк в двойных кавычках. Мы должны добавить некоторое обсуждение того, что происходит с экспортируемыми массивами.

Пользователи могут размечать строки, например, set SOMEPATH (string split : $SOMEPATH) .

Недостатком объединения экспортируемых переменных в пространстве является то, что они изменяются при рекурсивном запуске fish. Сегодня это работает:

> set -x list 1 2 3
> count $list
3
> fish -c 'count $list'
3

Но если бы мы экспортировали с пробелами, это показало бы 1 для рекурсивного вызова. Как вы сказали, мы не полагаемся на это, но это хорошо с точки зрения согласованности.

Спасибо за ваш вдумчивый ответ.

Я должен второй, что! Всегда приятно иметь свежий взгляд на вещи.

Для тех, кто плохо знаком с этим обсуждением, я думаю, что мне придется внести некоторые вещи, связанные с этим.

Что сразу приходит на ум, так это listify whitelist , который появляется в таких проблемах, как #2090.

Это означает, что для $PATH, $CDPATH и $MANPATH они будут отображаться как списки/массивы для вылова, но при экспорте они будут снова объединены с помощью «:». Затем рыба-внутри-рыбы снова разделит их. Это работает с двоеточиями, а не с \x1e. Судя по моему пониманию кода , он делает это для каждого двоеточия, без возможности выхода, поэтому он может сломаться в записях $PATH с двоеточием внутри них, что UNIX допускает внутри путей к файлам, хотя это кажется сломанным для $PATH по крайней мере . Эта схема также используется, например, для PYTHONPATH и GOPATH.

Я хотел бы иметь что-то более явное для разделения переменных среды, чем неявное всегда-разделить-на-\x1e-за исключением-этих-трех-разделить-их-на-двоеточии, потому что на самом деле это две разные схемы в one и экспорт списка в настоящее время всегда будет путать все, кроме рыбы.

Моим предпочтительным решением была бы такая функция, как splitenv var1 var2 var3 :

function splitenv --no-scope-shadowing
    set -e IFS # string split doesn't have superpowers, so unset IFS lest we split on both : and \n
    for arg in $argv
        set -q $arg; and set $arg (string split ":" $$arg)
    end
end

(Если бы у string split были сверхспособности , это было бы немного проще)

Все списки затем будут объединены двоеточием при экспорте, поэтому пользователь может явно разъединить их с помощью splitenv (хотя я не зациклен на вспомогательной функции, я действительно считаю, что сделать это тривиальным — это хорошо). вещь которую нужно сделать). Для обратной совместимости splitenv PATH CDPATH MANPATH будет выполняться при запуске. Если пользователь хочет экспортировать его по-другому, доступен string join .

Все это означает, что нам больше не нужен \x1e, у нас есть схема, которая, по крайней мере, имеет шанс быть понятой другими программами, но (довольно экзотическая ИМХО) рыба-внутри-рыбы теперь становится fish -c 'splitenv list; count $list' .

Проблема, конечно, в том, что, как уже упоминалось, обычная схема списка, разделенного двоеточием, не имеет способа избежать двоеточия, и если бы мы захотели добавить его, string split не имеет "--unscaped" возможность разделения только на неэкранированные разделители.

Я имею какой-то смысл?

@faho Я думаю, что эта идея заслуживает внимания. Худшая часть старой схемы заключалась в неявном разделении по двоеточиям, что искажало переменные, которые не должны быть разделены. В вашей идее это (почти) всегда явно, поэтому я думаю, что это вполне безопасно.

Что касается экранирования, отсутствие экранирования двоеточия в PATH является преднамеренным в соответствии с найденной вами ссылкой. Я сомневаюсь, что PYTHONPATH, CLASSPATH и т. д. более последовательны в этом отношении. Поскольку вы не можете использовать двоеточие в этих путях, мы можем решить, будем ли мы избегать его; но если мы избегаем двоеточия, нам нужно избегать обратной косой черты, и я уверен, что вы можете использовать обратную косую черту в PATH. Нам может понадобиться белый список «не избежать» (тьфу).

В качестве альтернативы мы не беспокоимся об этом и просто позволяем любому двоеточию выступать в качестве разделителя. Думаю, я склоняюсь к этому из-за простоты и знакомства с другими оболочками.

Мы по-прежнему сталкиваемся с проблемой, что некоторые спископодобные переменные разделены пробелами, а другие — двоеточиями. Одна возможность состоит в том, что splitenv принимает разделитель, запоминает его и использует для восстановления значения при экспорте:

splitenv --on ' ' LESS
splitenv --on ':' PYTHONPATH

Эти вызовы теперь играют двойную роль: импортируют любую существующую переменную и отмечают, как она экспортируется. Как вы думаете?

Кроме того, есть ли способ сделать это без редактирования config.fish? Может быть, как часть универсальных переменных?

Мы по-прежнему сталкиваемся с проблемой, что некоторые спископодобные переменные разделены пробелами, а другие — двоеточиями. Одна из возможностей заключается в том, что splitenv принимает разделитель, запоминает его и использует для восстановления значения при экспорте:

Звучит неплохо. Хотя на тот момент создание скрипта splitenv, вероятно, не помогло бы, так как нам в любом случае потребуется сотрудничество со стороны C++.

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

Возможно, сейчас "splitenv" уже не идеальное название (так оно и было, когда я об этом подумал, конечно :смеется: ) - я также подумал о "listify".

Хотя меня беспокоит то, что я не могу вспомнить, где у нас уже было подобное обсуждение раньше, я думаю, что мне нужно будет снова просмотреть проблемы сегодня вечером.

Пользователи могут размечать строки, например, set SOMEPATH (string split : $SOMEPATH) .

Команда string не задокументирована нигде, что я могу найти. Кроме того, man string показывает man-страницу string(3), в которой описаны функции работы со строками в BSD (и Mac OS X).

Но если бы мы экспортировали с пробелами, это показало бы 1 для рекурсивного вызова. Как вы сказали, мы не полагаемся на это, но это хорошо с точки зрения согласованности.

Однако такое поведение вызывает удивление. Я готов поспорить, что если вы спросите 100 человек, что происходит, когда экспортируется var с более чем одним элементом, 90 из них скажут, что значения объединены пробелом в качестве разделителя. Некоторые могут сказать, что в качестве разделителя используется запятая или другой символ. И два человека, которые запустили env , скажут, что значения объединены без разделителя, потому что, если вы не отфильтруете вывод с помощью чего-то вроде cat -evt , символ разделителя записи будет невидим.

который появляется в таких проблемах, как # 2090

Извините, но я не вижу смысла в жалобе этого пользователя. Проблема легко решается явной проверкой того, установлен ли уже MANPATH. Что, как мне кажется, вы должны сделать в любом случае, учитывая семантику начальных и конечных двоеточий.

поэтому он может сломаться в записях $PATH с двоеточием внутри них

По крайней мере, лет на тридцать уже поздно, чтобы исправить это. Мы не должны реализовывать экранирование двоеточий (и, соответственно, escape-символа), поскольку это было бы нестандартным поведением. До недавнего времени я более 20 лет работал специалистом по поддержке UNIX. Я никогда не слышал, чтобы кто-то жаловался, что наличие двоеточия в каталоге, встроенном в $PATH или аналогичную переменную, было проблемой.

Моим предпочтительным решением была бы такая функция, как splitenv var1 var2 var3

Это нормально, хотя непонятно, почему (недокументированных) string split недостаточно. Независимо от того, нужна ли нам новая функция, мы определенно не должны добавлять какие-либо новые переменные env с автоматическим разделением. Единственные два, которые достаточно распространены, чтобы гарантировать такое поведение, — это PATH и CDPATH (и MANPATH, поскольку он уже имеет особый регистр). Другие переменные, такие как PYTHONPATH, могут быть явно разделены пользователем, если он сочтет это полезным.

Однако, сказав, что, безусловно, должен быть способ зарегистрировать, что данная переменная (например, PYTHONPATH) должна иметь свои элементы, объединенные с определенным символом-разделителем при экспорте. Самый естественный способ сделать это — использовать новую опцию для команды set . Например,

set -x -S ':' PYTHONPATH dir1 dir2 dir3

Это не повлияет на то, как var хранится в универсальном хранилище данных var, где по-прежнему будет использоваться символ-разделитель записей, и он будет автоматически разделен при загрузке из этого хранилища данных. Необходимо определить, должен ли зарегистрированный символ-разделитель для экспорта влиять на интерполяцию строк. Я чувствую, что так и должно быть. То есть, если указанная выше команда «установить» выполнена, то последующая

echo "PYTHONPATH is $PYTHONPATH"

следует использовать двоеточие, а не пробел для объединения значений PYTHONPATH. Разделитель по умолчанию — это пробел для сохранения существующей семантики и минимизации неожиданностей для пользователя. Обратите внимание, что переменные в специальном регистре, такие как PATH, также будут использовать двоеточие в этом примере. Что несовместимо с текущим поведением, но согласуется с новой семантикой и менее удивительно. Другими словами, почему элементы $PATH разделены двоеточием в экспортируемой среде, а пробелы в выходных данных

echo "PATH is $PATH"

Строковая команда не задокументирована нигде, что я могу найти. Кроме того, справочная строка показывает справочную страницу string(3), в которой описаны функции работы со строками в BSD (и Mac OS X).

Легкий тигр. Это в версиях для разработки - см. https://github.com/fish-shell/fish-shell/blob/master/doc_src/string.txt .

Это нормально, хотя неясно, почему (недокументированного) разделения строк недостаточно.

Моя первоначальная идея заключалась в том, что это функция удобства, поэтому эта операция становится совершенно тривиальной. С предложением @ridiculousfish это становится чем-то большим и настраивает какое-то хранилище, поэтому переменная также будет присоединена к этому символу при экспорте. string split — это просто команда, которая разбивает строку — в основном наша версия cut .

Самый естественный способ сделать это — использовать новую опцию для команды set.

Это еще один вариант, хотя я не полностью уверен в семантике. Например, set -S ':' PYTHONPATH . Будет ли это устанавливать PYTHONPATH в пустой список или он просто разделит существующий PYTHONPATH? До сих пор все установленные параметры выполняли первое, поэтому вам нужно будет сделать set -S ':' PYTHONPATH $PYTHONPATH . Или мы заставим это _не_ делать это и получим несоответствие в одном и том же инструменте.

Другими словами, почему элементы $PATH разделены двоеточием в экспортируемой среде, а пробелы в выводе echo "PATH is $PATH"

На самом деле это хороший вопрос. Конечно, вы не ожидаете, что разделитель появится, скажем, в for p in $PATH; echo $p; end , но объединение его с разделителем char для каждой переменной может быть правильным решением. Конечно, есть string join , чтобы сделать это вручную.

Однако такое поведение вызывает удивление. Я готов поспорить, что если вы спросите 100 человек, что происходит, когда экспортируется var с более чем одним элементом, 90 из них скажут, что значения объединены пробелом в качестве разделителя.

Есть общая проблема с проектированием на основе опроса и ловлей рыбы. Потому что опрошенные часто имели представление о bash (и в меньшей степени о других оболочках POSIX), в то время как сама идея fish заключается в том, чтобы сделать что-то _лучше_, отказавшись хотя бы от части POSIX.

Это не значит, что это совершенно бесполезно, это просто то, что нужно иметь в виду - если бы мы придерживались таких идей, у нас было бы поведение bash с разделением слов и if-fi.

Будет ли set -S ':' PYTHONPATH устанавливать PYTHONPATH в пустой список или он просто разделит существующий PYTHONPATH?

Это установит его в пустой список. Если пользователь хочет сохранить существующее значение, он должен явно указать его (см. ниже).

У нас уже есть все необходимые возможности, за исключением средств для настройки символа (или пустой строки), который будет использоваться при объединении элементов массива данной переменной для экспорта или интерполяции. Если кто-то хочет манипулировать переменной типа PYTHONPATH, он может рассматривать ее как простую строку:

set PYTHONPATH "/a/new/dir:$PYTHONPATH"

Или они могут рассматривать его как массив:

set -S ":" PYTHONPATH /a/new/dir (string split ":" $PYTHONPATH)

Обратите внимание, что мое предложение использовать символ разделения/объединения вместо пробела при интерполяции в строку обеспечивает согласованное поведение независимо от того, разбивает ли пользователь var на массив.

Я определенно не предлагаю разработку комитетом. На этом пути лежит безумие и чушь вроде зш. Я просто указываю на то, что при наличии двух или более вариантов без какой-либо другой причины выбрать один из них, тогда выбор варианта, который меньше всего удивит пользователя оболочки, является лучшим выбором. Именно поэтому я (на данный момент) против введения новых команд или поведения, таких как автоматическое разделение переменных (кроме PATH и CDPATH, конечно). Это то, что делается нечасто и обычно только в config.fish и нескольких специализированных функциях, таких как скрипт «активировать» Anaconda. И способ заставить последний вести себя правильно, независимо от того, разделил ли пользователь var на массив в своем config.fish или нет, состоит в том, чтобы всегда рассматривать его как строку, которую необходимо разделить. Например, если нужно изменить PYTHONPATH, можно сделать что-то вроде этого:

# Hypothetical snippet from the Anaconda activate script.
if test (count PYTHONPATH) -gt 1
    set -S ':' PYTHONPATH /activated/python/tree $PYTHONPATH
else
    set PYTHONPATH "/activated/python/tree:$PYTHONPATH"
end

Или, проще говоря,

# Hypothetical snippet from the Anaconda activate script.
set -S ':' PYTHONPATH /activated/python/tree (string split ':' $PYTHONPATH)

Да, это потенциально превращает то, что могло быть простой строкой, в массив. Но с моим правилом, что символ, указанный переключателем -S , используется при экспорте и интерполяции, это преобразование в массив не должно иметь значения на практике. Однако есть один краеугольный случай. Что произойдет, если пользователь явно не преобразовал var в массив в своем config.fish, а затем запустит что-то вроде гипотетического сценария выше. var потенциально становится многоэлементным массивом, что означает, что если они впоследствии сделают

for elem in $PYTHONPATH
   echo $elem
end

Это не выполнит тело цикла for только один раз со значением в виде каталогов, разделенных двоеточием, как может ожидать пользователь, поскольку он не знал о разделении, выполненном гипотетическим скриптом «активировать». Я думаю, что мы можем смириться с этим, поскольку для пользователя было бы извращением делать что-то подобное.

tl; dr Я думаю, что списки должны «запоминать» свой разделитель, и ниже показано, почему.


Я согласен со многим из вышеперечисленного. Одна вещь, которая все еще кажется утомительной, заключается в том, что приведенные выше команды все еще кажутся чрезмерно многословными; т. е. иногда проще описать некоторые из этих команд простым английским языком.

В качестве примера (и я не столько сосредотачиваюсь на длине, сколько на количестве повторяющихся вещей):

  • рыба: set -S ':' PYTHONPATH /activated/python/tree (string split ':' $PYTHONPATH)
  • Английский: «добавить /activated/python/tree к PYTHONPATH ( : -с разделителями`)»

Здесь есть две повторяющиеся вещи: PYTHONPATH и разделитель : . Повторение PYTHONPATH допустимо по двум причинам, и ни одна из этих двух причин не применима к разделителю.

  1. Нетрудно интуитивно понять, что происходит, когда кто-то говорит set PYTHONPATH /activated/python/tree $PYTHONPATH , потому что это очень похоже на такие вещи, как i = 2 + i , что является очень знакомым понятием/идиомой. (Но у нас все еще есть ярлыки, такие как += , поэтому ниже я предлагаю флаг --append .) С другой стороны, когда люди думают о добавлении к списку, они не думают о разделении. и присоединение к разделителю. Они не думают о том, чтобы преобразовать весь список в какой-то другой формат, выполнить с ним реальную операцию и вернуть его обратно. По их мнению, они, естественно, читают разделитель как разделитель вместо того, чтобы менять его на какой-то «внутренний» или «предпочтительный» разделитель.
  2. Использование простой команды set для добавления сохранений позволяет добавить еще одну команду для объединения двух разных списков. С другой стороны, преобразование одного разделителя в другой — это то, что мы в идеале никогда не хотим, чтобы пользователь выполнял вручную, в основном по вышеуказанной причине.

Напротив, я предлагаю другой способ указать разделитель в списках: связать его со списком на неопределенный срок. Таким образом, приведенный выше пример может быть выполнен следующим образом:

# Changes the delimiter for this list. This might be done in some global config file for common lists as this one.
set -S ':' --no-modify PYTHONPATH
# or, workaround if you don't want to add extra options to set:
set -S ':' PYTHONPATH $PYTHONPATH

# The actual append operation
set --prepend PYTHONPATH /activated/python/tree
# or, workaround if you don't want to add extra options to set:
set PYTHONPATH /activated/python/tree $PYTHONPATH

Последствия/дополнительные вопросы/и т. д.:

  1. Это вполне совместимо с текущим предложением. Вот необходимые изменения:

    • Закрепите разделитель (возможно, используя другую переменную как __fish_sep_PYTHONPATH )

    • (необязательно) Добавьте флаг, который я в настоящее время вызываю --no-modify , который сообщает fish изменить разделитель списка без изменения его содержимого. Возможно также добавить флаги --append и --prepend по причине (1) выше. В любом случае, это не требуется, как показано в обходном пути выше, подобно тому, как добавление и добавление в начале выполняются в рыбе сегодня.

  2. В рыбе со списками нужно обращаться как минимум как с гражданами первого сорта. Это означает, что изменение разделителя должно изменить строковое представление, а не представление списка (если только разделитель не присутствует в одном из элементов, и в этом случае разделение неизбежно). Например, если вы меняете разделители с , на : , ["0:1", "2"] должно стать ["0", "1", "2"] , а не ["0", "1,2"] (это то, что произойдет, если вы просто измените разделитель, не меняя строку, поддерживающую список). Это поведение должно максимально соответствовать текущему поведению и тому факту, что в настоящее время существует неизменяемый разделитель по умолчанию.

Вот суть:

  • Это требует намного меньше токенов, и почти ничего не повторяется.
  • Это соответствует ментальной модели многих пользователей. Пользователи думают такими терминами: «добавить», «установить разделитель», «не изменять».
  • Это выглядит как единственно правильный способ решения этой задачи (старый способ теперь выглядит очень неуклюжим), и поэтому эти дополнения не разрушают ортогональности.
set --no-modify -S : PYTHONPATH
set --prepend PYTHONPATH /activated/python/tree

Спасибо, @szhu , за подробный комментарий относительно моего предложения. Тем не менее, есть много проблем с предложенным вами решением. Например, добавление опции --no-modify фактически изменяет переменную, преобразовывая ее в список, и, таким образом, изменяет переменную. Хотя я отвергаю почти все элементы вашего предложения, оно заставило меня задуматься о более простом решении, которое учитывало бы большинство, если не все, ваши вопросы. Возможно, должен быть механизм, сообщающий рыбе, что данный env var всегда должен автоматически разделяться и воссоздаваться на данном токене (например, ":" или " "). Это можно назвать автоматическим обозначением массива, и при выполнении любое существующее значение будет немедленно разделено, если оно еще не было массивом.

В команду set можно добавить новую опцию, чтобы активировать это поведение. Однако я обеспокоен тем, что это неоднозначно и может быть истолковано как определение переменной без значения. Будет ли однозначным добавление параметра токена -A к команде set ? Например:

set -x -A ':' PYTHONPATH

Предположительно, это немедленно преобразует любую существующую переменную окружения PYTHONPATH в массив после разделения на двоеточие. Это, наоборот, приведет к объединению значений в двоеточие при экспорте или интерполяции в строку. Точно так же, даже если PYTHONPATH не существовало во время выполнения этой команды, спецификация автоматического массива была бы запомнена, и это повлияло бы на последующие использования. Например, это, очевидно, создаст массив:

set PYTHONPATH /a/path /b/path /c:/d/path

Но как насчет последнего аргумента? Должен ли он автоматически разделяться на два токена?

Обратите внимание, что это поведение должно применяться только к экспортируемым переменным, в противном случае возникнет ошибка. Есть также некоторые угловые случаи, которые необходимо разъяснить. Например, что, если исходное объявление автоматического разделения включает значения, как в этом примере:

set -x -A ':' PYTHONPATH 'hello:goodbye' $PYTHONPATH

Должны ли эти значения быть разделены на токене автоматического разделения? Или это должно привести к ошибке и потребовать изменения значения в отдельном выражении? И какой бы синтаксис ни был выбран, у вас по-прежнему возникает вопрос, что делать со значениями, содержащими маркер автоматического разделения. Дьявол кроется в деталях. То есть могут быть другие ответвления этого предложения, о которых я не думал. Насколько я могу судить, мое первоначальное предложение с более подробным синтаксисом позволяет избежать этих проблем.

@krader1961 , спасибо за ответ. Однако вы, кажется, думаете, что я преобразовываю переменные из строк в списки. Я думаю, вы неправильно понимаете одну важную концепцию в fish: каждая переменная представляет собой список строк . Переменные, которые кажутся строками, на самом деле являются списками длины 1. fish обрабатывает их так же, как списки длины 0 или 2 или любой другой длины.

Кроме того, обратите внимание, что хотя базовая строка, используемая для передачи переменных среды, может измениться при изменении разделителей, одна из сильных сторон fish заключается в том, что пользователю обычно вообще не нужно думать о разделителях. Вот почему я рекомендую, чтобы все, что делает параметр -S , это указывало, как этот список должен быть преобразован в строку, когда он _экспортируется наружу_ fish. -S не должен изменять представление внутреннего списка (за исключением случаев, когда невозможно представить этот список с помощью целевого разделителя).

Кстати, вот один пример, который показывает, насколько чисто мое предложение. Вот код для преобразования переменной $L обратно в разделитель по умолчанию \x1e . Это абсолютно не повлияет ни на одну переменную (любую область видимости, любое количество элементов), которую сегодня можно создать в fish.

set -S \x1e L $L

Еще одна вещь: семейство аргументов --no-modify — это просто ярлыки. Вот их эквиваленты:

| ярлык | эквивалент |
| --- | --- |
| set [other args] --no-modify L | set [other args] L $L |
| set [other args] --prepend L $TOADD... | set [other args] L $TOADD... $L |
| set [other args] --append L $TOADD... | set [other args] L $L $TOADD... |

(Я заявлял следующее раньше, но думаю, что могу лучше объяснить это сейчас.) Подчеркивая, насколько «тупыми» являются эти три аргумента, некоторые могут задаться вопросом, нужны ли они вообще. Можно сослаться на то, что у рыбы есть принцип ортогональности . Когда все вещи ортогональны, это означает, что для любой большой задачи, которую вы хотите выполнить, должно быть очевидно, какой набор функций выбрать для этой задачи — должен быть только один правильный способ ее выполнения. Здесь я действительно добавляю другой способ добавления/добавления/предотвращения модификации списка, но это только потому, что я считаю, что заменяемые эквиваленты излишне многословны; они не должны быть правильными способами добавления списков изменений. Один из способов убедиться в этом — подумать о том, как вы думаете о добавлении к списку. Вы, вероятно, думаете, что «добавьте $TOADD к $L », а не «установите $L к $L $TOADD ».

Дайте мне знать, что вы думаете, и делает ли это более убедительным аргументом в пользу моего предложения. (Кроме того, я довольно часто неправильно понимаю вещи, поэтому не стесняйтесь меня поправлять.)

@szhu Я прекрасно знаю, что все переменные в fish представляют собой списки из нуля, одного или нескольких значений. Вы также, по-видимому, не читали мои более ранние комментарии, в которых я четко заявляю, что связанный разделитель не должен влиять на внутреннее представление или на то, как значения сохраняются в универсальном хранилище данных (кроме сохранения разделителя). Вы также не рассмотрели мои предыдущие пункты. Рассмотрим ваш последний пример:

set -S \x1e L $L

Что делать, если L уже содержит два или более значений? Предположительно ничего, кроме изменения связанного разделителя. Будет ли в этом случае аргумент $L необязательным? Или он должен сначала преобразовать существующий массив в простую строку (предположительно, конкатенируя с использованием существующего разделителя), а затем разделить эту строку на новый разделитель? Как я уже говорил, дьявол кроется в деталях.

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

Извините, эта ветка длинная, я, должно быть, пропустил ваше признание этого выше; приятно знать, что мы на одной волне! Я думаю, что я рассмотрел большинство ваших проблем выше, но не все. Ниже я подробно рассмотрю каждую из ваших проблем.


1. Является ли $L необязательным в set -S \x1e L $L ?

Существующее поведение set не изменится. При текущем поведении set L $L не изменяет L , а set L делает L пустым списком. То же самое с set -S \x1e L $L и set -S \x1e L .

1.1 Не кажется ли set -S \x1e L $L слишком многословным для простого изменения разделителя?

Немного. Вот почему я предлагаю вариант --no-modify в качестве ярлыка для этого.

Но мой план не рухнет, если этого ярлыка не будет. Мы уже сталкиваемся с этой проблемой каждый день, когда добавляем списки: set PATH ~/.bin $PATH . Вот почему, по той же причине, я предлагаю также --prepend и --append .

2. Как будет происходить процесс преобразования?

Допустим, наш старый разделитель — \x1e , а новый — : , и что у нас есть список рыб ["hello", "world"] (экспортируется как hello\x1eworld ). Существует два основных способа преобразования (" варианты преобразования "):

  1. Используйте ["hello", "world"] и преобразуйте его в ["hello", "world"] (экспортируется как hello,world )
    Преимущество: представление списка не меняется.
  2. Используйте hello\x1eworld и преобразуйте его в ["hello\x1eworld"] (экспортируется как hello\x1eworld )
    Преимущество: представление экспортируемого значения не меняется.

Обратите внимание, что это с точки зрения пользовательского интерфейса, а не с точки зрения реализации; мы говорим о том, как это выглядит для пользователя. Я расскажу о реализации в следующем вопросе. _Примечание: остальная часть этого ответа - это новые вещи, которые я не упомянул выше, вызванные вашими вопросами. Спасибо!_

Внутри рыбы. Во-первых, если мы работаем исключительно с рыбой, списки — это первоклассно, и вам никогда не придется беспокоиться о разделителях, и поэтому они не требуются. (Опять же, «должен» с точки зрения пользователя, поскольку мы, как разработчики, несем ответственность за то, чтобы это было правдой.)

Изменение формата экспорта переменных. Таким образом, единственная причина, по которой пользователю потребуется изменить разделители, — это изменение экспортируемой строки для программ, считывающих переменные среды. Для списков, созданных в fish, мы обязательно будем использовать вариант преобразования 1 , потому что значение переменной как списка важно и четко определено, поэтому нам нужно сохранить представление списка.

Изменение формата импорта vars. Однако для переменных среды, таких как PATH , которые изначально создаются вне fish, нам нужно для списка, в котором уже есть разделитель, указать fish, что это за разделитель. Для этого мы можем использовать вариант преобразования 2 .

2.1 Как это будет реализовано?

Fish, несмотря на то, что пользователю не нужно знать об этом, fish на самом деле хранит списки в виде строк. Переменная x хранится как hello\x1eworld . По моему предложению должна быть еще одна переменная, __fish_delimiter_x , которая указывает разделитель переменной x . Сейчас его не существует, поэтому мы используем разделитель по умолчанию, \x1e .

Для варианта преобразования 1:

  1. Разбить переменную по старому разделителю, в результате чего получится истинный список на языке реализации (C++).
  2. Присоединитесь к списку, используя новый разделитель, в результате чего получится новая строка.
  3. Сохраните новый разделитель в __fish_delimiter_x .

Для варианта преобразования 1 эквивалентная реализация:

  1. В переменной замените все вхождения старого разделителя на новый.
  2. Сохраните новый разделитель в __fish_delimiter_x .

Для варианта преобразования 2:

  1. Сохраните новый разделитель в __fish_delimiter_x .

2.2 Если нам нужны оба варианта преобразования, как пользователь укажет, какой из них использовать?

Возможно, у нас может быть два варианта: -D или --convert-delimiter для варианта 1 и -d или --set-delimiter для варианта 2.

2.3 Действительно ли нам нужны оба варианта?

Под текущей рыбой мы решили предположить, что мы не увидим \x1e в дикой природе, кроме рыбы. Если мы сохраним это как разделитель по умолчанию и сохраним это предположение, вариант преобразования 1 достаточен как для преобразования, так и для установки разделителя, и нам не понадобится вариант преобразования 2 . (Легкий способ убедиться в этом — понять, что если предположение верно, то при преобразовании списков, созданных извне, шаг варианта преобразования 1 «заменить все вхождения старого разделителя новым» ничего не даст, сократив все преобразование. к варианту преобразования 2.)


@ridiculousfish , я также был бы признателен за ваши отзывы об этом, особенно в отношении пользовательского интерфейса и деталей реализации. Спасибо!

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

+1 за истинный массив

Этот трюк с разделителем действительно нужен для рыбы? Пинг #627

Возвращаясь к этому в свете моего исправления ошибки № 2106, в которой я заметил, что существует два несовместимых способа преобразования строкового представления значений переменных в массивы. Один из которых неправильно исключал пустые элементы. Основная проблема заключается в том, что class env_var_t основано на wcstring , а не на векторе wcstring. Вопрос о том, стоит ли менять это усилий, остается открытым.

Если вы следите за этой проблемой, я рекомендую вам взглянуть и, возможно, протестировать PR № 4082. Я решил, что лучший способ решить эту проблему — это «связанные» переменные, похожие на одноименную функцию в zsh.

Похоже, что вопросы, связанные с этими списками, экспортируемыми через двоеточие, и какие envvars должны быть включены в этот белый список, еще не решены. Каков текущий статус по этому вопросу? Можно ли надеяться на окончательное решение этой темы? Буквально сегодня я снова столкнулся с ловушкой, что LD_LIBRARY_PATH отсутствует в белом списке...

Подводя итог: переменные среды Unix являются строками, поэтому переменные окружения, подобные массивам, должны использовать разделитель. В большинстве случаев используются двоеточия ($PATH); хотя не все делают ($ МЕНЬШЕ). Мы хотели бы просто использовать двоеточия для разграничения всех массивов при импорте/экспорте (и действительно рыба раньше работала таким образом); проблема в том, что некоторые плоские переменные содержат двоеточия ($DISPLAY, $SSH_CONNECTION).

Цель состоит в том, чтобы заставить переменные с разделителями работать естественно с поддержкой массива fish. @szhu предложил улучшить set для отслеживания разделителя, но расширение IMO set — неправильное место для присоединения этого:

  • Раздражающее взаимодействие между установкой переменной и установкой ее разделителя (мотивация --no-modify ).
  • Каверзные вопросы о том, как разделители взаимодействуют с областью видимости переменной.
  • Проблемы с универсальными переменными. Нам придется научить uvar запоминать разделитель, а также около --no-modify , поскольку с помощью uvar невозможно установить переменную в ее текущее значение.

В обзоре я одобряю идею splitenv @faho . splitenv name разделит существующую переменную на двоеточия, вот и все. Это удивительно просто. Переменные, в которых не используются двоеточия, достаточно редки, поэтому для них не нужна специальная поддержка.

Недостатком является то, что экспортированные массивы fish будут повторно импортированы в виде строки, разделенной двоеточием; на практике я думаю, что это будет редко.

Мы не должны навязывать пользователям это осложнение на splitenv , если можем его избежать. Итак, я хочу сделать еще один шаг и расширить белый список двоеточий на все переменные среды, имена которых заканчиваются на PATH , например, LD_LIBRARY_PATH, PYTHONPATH и т. д. На практике это должно работать правильно почти все время; любой, кого он укусил, может использовать string join , чтобы исправить значение.

Итак, что я предлагаю (на самом деле предложение Фахо):

  • Экспорт всех массивов с использованием двоеточий; больше нет разделителя записей ASCII.
  • Реализуйте функцию splitenv , которая разбивает переменную на двоеточия. Это может быть написано в сценарии рыбы.
  • Расширьте белый список, разделенный двоеточиями, для всех переменных, оканчивающихся на PATH.

Я считаю, что это решит большую часть проблем, связанных с массивами, разделенными двоеточием, минималистичным и совместимым способом.

относительно идеи splitenv:

Допустим, я хотел, чтобы fish экспортировал список, элементы которого содержат двоеточие, например: ["item1", "item:2"] . (Я не думаю, что это редкое явление, особенно когда массивы используются для хранения пользовательского ввода.)

Будет ли список экспортирован как item1:item:2 ? В этом случае будет невозможно воссоздать исходный список после экспорта.

Кроме того, наличие неизменяемого белого списка для переменных кажется неправильным, хотя наличие белого списка *?PATH кажется менее неправильным. (Это была еще одна причина, по которой я предложил хранить разделитель как переменную — белый список можно изменить, установив переменную.)

@szhu Ты прав. Exported-lists-can't-contain-colons — это проблема, от которой уже страдает Unix:

С \

поэтому я не слишком расстраиваюсь из-за введения такого же ограничения для рыбы (только для экспортируемых переменных).

Также эта проблема возникает только при экспорте массива в рекурсивно вызываемый экземпляр рыбы, что, я думаю, будет редко. Если это окажется распространенным явлением, мы могли бы либо добавить данные sidecar в другую переменную, либо использовать другой разделитель массива при рекурсивном вызове fish. Думаю, нам не нужно будет заходить так далеко.

Я согласен с тем, что крайний случай, когда предложение не работает, не очень распространен, но я боюсь, что было бы очень плохо, если бы люди столкнулись с этим.

Вот пример, который является лишь частично надуманным:

set -x TEST color:red 
set -x TEST2 color:red font:serif
set -x TEST_PATH color:red 
set -x TEST2_PATH color:red font:serif
exec fish
echo $TEST #=> color:red
echo $TEST2 #=> color:red:font:serif
echo $TEST_PATH #=> color red 
echo $TEST2_PATH #=> color red font serif

Я могу представить, как многие новые пользователи будут сбиты с толку, увидев вышеизложенное.

Я думаю, что следующее поведение было бы значительно более приятным:

set -x TEST color:red 
set -x TEST2 color:red font:serif
set -x TEST_PATH color:red 
set -x TEST2_PATH color:red font:serif
exec fish
echo $TEST # color:red
echo $TEST2 # color:red font:serif
echo $TEST_PATH #=> color:red 
echo $TEST2_PATH #=> color:red font:serif

Мне бы хотелось, чтобы вы и сообщество думали об этом.

Почему бы не избежать существующих двоеточий? Это позволит сохранить различие.

Побег имеет смысл для меня.

Может ли все еще сбивать с толку то, что переменная не будет запоминаться, является ли она массивом?

set -x TEST2 color:red font:serif
set -x TEST2_PATH color:red font:serif
exec fish
echo $TEST2 # color\:red:font\:serif
echo $TEST2_PATH #=> color:red font:serif

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

MANPATH имеет особое значение для двойных двоеточий (::) — см. # 2090 — мешает ли это работе?

Я также утверждаю, что наличие дополнительной переменной FISH_ARRAY_VARIABLES=FOO\t:\nBAR\t;\nBAZ\t-\n в любом случае было бы хорошей подсказкой для экземпляров Fish, вызываемых для повторного выбора переменных массива, не мешая другим процессам и не требуя «мы вовлечение рыбы сейчас" шашка..

re: https://github.com/fish-shell/fish-shell/issues/436#issuecomment -392409659 @zanchey
Я не читал # 2090 подробно, но я считаю, что преобразование между строками, разделенными двоеточием, и формами массива полностью бесшовно (за исключением случаев, когда двоеточие ~ не появляется ~ появляется в элементах массива).

Чтобы включить двойное двоеточие в MANPATH , просто добавьте пустую строку там, где должно стоять двойное двоеточие:

$ set -x MANPATH 1 2 '' 3
# Check if it's set
$ bash -c 'echo $MANPATH'
1:2::3

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

$ set -x MANPATH '' 1 2 3
# Check if it's set
$ bash -c 'echo $MANPATH'
:1:2:3

Я не следил за всем здесь, но как пользователь я хочу выступать за «без конфигурации».
Я думаю, что set -S и splitenv — это формы конфигурации. Некоторые пользователи делают это в fish.config и обрабатывают PYTHONPATH как массив. Другие не будут обрабатывать PYTHONPATH как одно слово, разделенное двоеточием. Копирование и вставка рекомендаций по переполнению стека и запуск сценариев, управляющих PYTHONPATH от одного пользователя к другому, не всегда будут работать...

Фиксированное правило «если оно заканчивается на PATH » не требует настройки и звучит настолько идеально, насколько это возможно :+1:
(у меня нет мнения о том, стоит ли обратная несовместимость)
Да, set -x TEST2_PATH color:red font:serif будет импортирован как массив color red font serif , но это касается экспорта переменных. Вы не можете установить экспортированную переменную в массив, не понимая, как она работает.

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

@ridiculousfish это может быть правдой в текущих оболочках, но я полагаю, что по мере того, как рыба набирает обороты, пользователи могут захотеть использовать способность рыбы отправлять списки дочерним оболочкам рыб. Я могу представить, что в конечном итоге могут появиться программы/плагины, которые управляют состоянием рыбной сессии (я вернусь к этому комментарию через несколько лет, чтобы убедиться, что это правда), и смогут универсально автоматически де/сериализовать списки. сделает этот код более чистым и менее обходным.


Вроде похожая, но немного другая мысль: рассматривать PATH как особый случай — это анахроничный пограничный случай, который пользователи, вероятно, понимают, только если у них есть история типичных случаев использования оболочек. Это ограничивает возможность использования fish в качестве общего языка сценариев и ограничивает некоторые потенциальные варианты использования в будущем.

@ridiculousfish Я думаю, что одно из возможных решений - связать каждую переменную/массив среды с ее собственным разделителем (и вы можете оставить '\x1e' или ' ' или ':' по умолчанию), и пользователь, который создает переменную среды, отвечает за выбор подходящих разделителей во избежание конфликтов. Команда может выглядеть так: set --separator ':' TMP 1 2 3 . Таким образом, для этих хорошо известных переменных среды пользователи могут просто выбрать соответствующие известные разделители, которые также могут распознаваться другими программами и могут сделать рыбу более совместимой с большим количеством программ (таких как Python).

Для тех, кто читает только последние комментарии, просто обратите внимание, что рекомендация @thuzhf set --separator совпадает с рекомендацией set -S , неоднократно упоминаемой в этой теме. Чтобы получить больше информации об этом обсуждении, вы можете выполнить поиск set -S на этой странице.

@szhu Извините, что не заметил предыдущую set -S . Я тоже в принципе этого хочу. Я также заметил, что у других было несколько опасений по поводу этой новой опции. Я могу изложить свои мысли по поводу этих опасений ниже (поскольку в наборе fish не используется -s в качестве опции, я буду использовать -s для ссылки на --separator дальнейшем):

  1. --no-modify что-то изменяет. Да, и вы должны изменить имя, чтобы оно было явным, например, --change-separator .
  2. Есть некоторые угловые/хитрые случаи. В основном это связано с нечетко определенным синтаксисом, и этого можно избежать, если мы дадим строгое определение синтаксиса. Например:

    1. Основная идея: каждый var (список) связан со своим собственным разделителем при определении (по умолчанию ' ' ). Этот разделитель будет использоваться, когда эта переменная создается из строки и когда она преобразуется в строку (это распространенная идея в некоторых языках, таких как функция Python join() ). Переменная преобразуется в строку при экспорте или когда пользователь хочет это сделать.

    2. Как создать env вары



      1. set ENV_VAR a b c . Без -s мы выбираем ' ' в качестве разделителя по умолчанию.


      2. set -s ':' ENV_VAR . В этом случае ENV_VAR устанавливается как пустой список.


      3. set -s ':' ENV_VAR a b:c d e:f . В этом случае пользователи, которые пишут этот код, должны четко понимать, что ':' — это разделитель, и понимать, что ENV_VAR будет массивом вроде ['a b', 'c d e', 'f'] и будет экспортироваться как 'a b:c d e:f' . Что, если вы хотите, чтобы экспортируемый ENV_VAR начинался с пробелов и заканчивался пробелами? Вы должны использовать escape-последовательности, такие как: set -s ':' ENV_VAR \ a b:c d e:f\ . Тогда ENV_VAR будет [' a b', 'c d e', 'f '] и будет экспортироваться как ' a b:c d e:f ' .


      4. set -s ':' ENV_VAR a b:c d e:f $ENV_VAR . В данном случае это зависит от того, как работает $ . Если она определена как извлечение строкового значения ENV_VAR вместо списка, то эта команда будет такой же, как простая замена $ENV_VAR ее строковым значением, преобразованным из нижнего списка, и в этом случае set -s ':' ENV_VAR a b:c d e:f:$ENV_VAR вероятно, то, что вы действительно хотите (обратите внимание на : после f ); если он определен как извлечение переменной ENV_VAR (которая представляет собой список, а не строку), то это должно стать операцией расширения списка, как в python. Например, в последнем случае, если ENV_VAR до этого было ['x', 'y'] , то после этой операции ENV_VAR станет ['a b', 'c d e', 'f', 'x', 'y'] . Что делать, если предыдущий разделитель ENV_VAR не равен ':' ? В первом случае вы несете ответственность за то, чтобы убедиться, что делаете все правильно, например, вам, вероятно, следует использовать согласованный разделитель, изменив исходный разделитель на ':' или изменив текущий разделитель на исходный. В последнем случае это установит разделитель этого массива от исходного (независимо от того, какой он есть) на ':' .



    3. Как изменить разделитель



      1. set --change-separator ':' ENV_VAR . Если ENV_VAR не существует, программа должна выйти с кодом ошибки, отличным от 0. Достаточно просто и понятно.



    4. Как посмотреть разделитель



      1. set --view-separator ENV_VAR .



Кроме того, я действительно думаю, что эта проблема очевидна и неотложна , и является большой проблемой для пользователей, и надеюсь, что эту проблему можно будет решить как можно скорее, потому что это действительно сильно влияет на пользовательский опыт. На самом деле я пока не сталкивался с другими (даже очень маленькими) проблемами при использовании рыбы, кроме вот такой большой.

Я действительно думаю, что эта проблема очевидна и актуальна

@thuzhf : я бы сказал, что ты переоцениваешь это.

Одна из причин заключается в том, что ваша проблема в #5169 была связана с $LD_LIBRARY_PATH, но на самом деле это не список в fish! Вы должны установить его как set LD_LIBRARY_PATH "$LD_LIBRARY_PATH:/some/path" , как и в других оболочках.

Fish автоматически превращает ровно три унаследованных/экспортированных переменных в списки:

$PATH, $MANPATH и $CDPATH. И именно этот список будет иметь разделитель ":" при экспорте.

Другие «стандартизированные» переменные, такие как $LD_LIBRARY_PATH, не должны обрабатываться как списки в fishscript, поэтому у вас нет этой проблемы. С нестандартизованными переменными вы можете обращаться как хотите, так как другие программы все равно ничего с ними делать не будут, так что разделитель не критичен.

@faho Спасибо за четкое объяснение. Это действительно имеет для меня большой смысл. Хорошо, я могу сказать, что эта проблема решена для меня.

Я рассмотрел проблему MANPATH, описанную в #2090. Сценарий состоит в том, чтобы добавить к manpath, чтобы он продолжал использовать системные пути.

В bash это можно было бы написать как export MANPATH="$MANPATH:/new/path" . Если установлен MANPATH, это будет добавлено к нему. Если не установлено, перед ним будет стоять двоеточие, которое указывает на необходимость использования системных каталогов. Этот синтаксис не работает в fish; проблема в том, что MANPATH — это массив, поэтому «$MANPATH» будет содержать пробелы вместо двоеточий.

Подход со «связанными переменными» позволил бы нам иметь, например, fish_manpath в виде массива, отражающего MANPATH в виде строки, разделенной двоеточием. Это может быть построено полностью в сценарии рыбы. Однако мы хотели бы сделать это для всех переменных, подобных пути, а не только для MANPATH, и это было бы значительным нарушением совместимости, с которым неясно, как справиться. Также у него есть те же проблемы, например, переменная-массив manpath в zsh неудобно добавлять, поэтому неясно, почему она вообще существует.

Мое предложение здесь не делает ситуацию с MANPATH лучше или хуже; Я думаю, что нужно сделать это и просто придумать простую историю для добавления к MANPATH, а именно:

set -q MANPATH || set MANPATH ''
set -x MANPATH $MANPATH /new/path

Это не так уж больно вставить в config.fish.

Мое предложение здесь не делает ситуацию с MANPATH лучше или хуже; Я думаю, что нужно сделать это и просто придумать простую историю для добавления к MANPATH, а именно:

@ridiculousfish : На самом деле я думал сделать еще один шаг: разделить эти специальные переменные на «:», также по присваиванию, и соединить их с помощью «:» вместо пробела в раскрытии в кавычках.

Это означает, что когда вы выполняете set -gx MANPATH "$MANPATH:/new/path" , fish переходит и выполняет разбиение автоматически, в результате чего получается эквивалент set -gx MANPATH "" /new/path .

Теперь это означает, что «:» не может появляться в пути в $MANPATH (и $PATH, и $CDPATH), но они все равно не могут этого сделать, потому что это нарушит утилиты, не относящиеся к рыбе!

Это также позволило бы нам, возможно, когда-нибудь удалить специальную обработку, потому что она добавляет кросс-совместимый способ обработки — вам просто нужно назначить с помощью : и использовать его с (string split : -- $MANPATH) , и это будет работать, даже если эта обработка будет удалена.

@faho Мне нравится идея - как пользователь пометит переменную как получающую эту особую обработку? Сделал бы это splitenv ?

как пользователь пометит переменную как получающую эту специальную обработку?

Моя идея заключалась в том, чтобы вообще не разрешать маркировку — просто оставить ее как особое поведение для $PATH и др. Что позволит нам уйти от листинга в какой-то момент в будущем.

Однако с тех пор я понял, что разрешение этого для других переменных помогает нам и с другими переменными - например, я сказал ранее, что мой $EDITOR установлен как один элемент ( set EDITOR "emacs -nw" ) для совместимости с внешними инструменты, но рыбам больше понравилось бы, если бы это был список.

Поэтому я бы, вероятно, по умолчанию использовал _space_ в качестве разделителя, если только он не похож на PATH (и если предположить, что это так, если имя заканчивается на PATH, это, вероятно, нормально).

Сделает ли это splitenv?

Мне не очень нравится вводить для этого еще одну встроенную функцию, поэтому я, вероятно, выберу опцию аргумента для установки.

Я согласен с тем, что "PATH/MANPATH/CDPATH в специальном регистре - это странно; нам нужно более общее решение".

Я предлагаю ОСТАНОВИТЬ использование PATH/MANPATH/CDPATH в специальном регистре. С ними будет обращаться (конечный пользователь рыбы) так же, как и в других раковинах. $PATH (и другие) будет одной строкой (или на рыбном жаргоне списком длиной 1) с двоеточиями в ней. Обратите внимание, что я имею в виду взаимодействие с пользователем fish, а не то, как эти вещи обрабатываются внутри; Я не знаю, как будет выглядеть реализация внутри fish — я полагаюсь на то, что другие укажут на любые проблемы.

Конечно, это будет иметь недостаток обратной несовместимости, но я думаю, что это стоило бы большого выигрыша в простоте и элегантности. Я думаю, что это также будет адрес # 2090.

Что все думают?

5245 был объединен, так что это кажется решенным.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги