Fish-shell: a caixa especial PATH/MANPATH/CDPATH é estranha; precisamos de uma solução mais geral, como variáveis ​​"amadas" zsh

Criado em 11 dez. 2012  ·  52Comentários  ·  Fonte: fish-shell/fish-shell

Em 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"

Isto resulta em:

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

É claro que o char \x1e é tratado especialmente como delimitador de elemento.

enhancement

Todos 52 comentários

A preocupação é que não há como representar \x1e? Ou você está pensando em melhorias arquitetônicas?

Eu acho que o separador de array é usado principalmente em arrays persistentes em lugares que só aceitam strings, como variáveis ​​universais ou variáveis ​​de ambiente.

2012-12-12 02:09,"ridiculousfish" [email protected]写道

A preocupação é que não há como representar \x1e? Ou você está pensando
sobre melhorias arquitetônicas?

Eu diria que tenho as duas preocupações em mente. Para o primeiro, basta pensar em um
nome do arquivo com \x1e incorporado. POSIX diz qualquer coisa, mas \0 é permitido em
nomes de arquivos, então é perfeitamente possível. Usar \0 como delimitadores de array pode ser
uma escolha um pouco melhor, mas isso leva à segunda preocupação - é
frágil e claramente errado.

Eu acho que o separador de matriz é usado principalmente em matrizes persistentes em lugares
que só aceitam strings, como variáveis ​​universais ou variáveis ​​de ambiente.

Se persistir significa "serializado", não. Arrays são sempre armazenados em
forma delimitada por \x1e. As matrizes de ambiente exportadas são unidas por ":". Elas
são usados ​​em variáveis ​​universais - qual IMHO deve ser implementado
com escape adequado em vez disso.


Responda a este e-mail diretamente ou visualize-o no GitHub.

Que tal usar um caractere de área de uso privado como separador? Fish já usa alguns deles em alguns casos.

@JanKanis Isso não é melhor; é perfeitamente possível em nomes de arquivos (considerando sistemas de arquivos usando não-utf8, codificações nativas) e outras strings.

Eu diria que, entre outros, "\0" é uma escolha _ligeiramente_ melhor entre outros, já que esse é o único caractere que o UNIX proíbe em nomes de arquivos, mas ainda tem o cheiro ruim para mim. Além disso, já estamos fazendo muita divisão e montagem de arrays, espero que implementar arrays verdadeiros resulte em melhor arquitetura e menos código.

Fish já lida com caracteres de uso privado e bytes inválidos quando codifica strings externas para wchars. Esses valores especiais são codificados byte a byte em um conjunto específico de caracteres de uso privado que o fish também decodifica novamente na saída, portanto, em princípio, usar outro caractere de uso privado pode funcionar. No entanto, concordo que usar matrizes verdadeiras é muito melhor. Há uma complicação em que a comunicação entre fish e fishd acontece em um soquete usando strings utf8, e lá o fish usa (eu acho) a sequência de escape "\x1e" (em vez de um byte 0x1e) para separar os itens da matriz. Mas isso provavelmente poderia ser resolvido usando, por exemplo, uma sequência de escape privada não utilizada.

Compartilho as preocupações de xiaq, mas (para as práticas) acho a divisão implícita em \n muito mais ofensiva:

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

A interpretação da matriz (delimitada por nova linha) da saída do subprocesso deve ser explícita e opcional!

Mas isso provavelmente não tem nada a ver com o armazenamento subjacente de arrays…

@xiaq : O que há de errado em usar \0 ? xargs parece usá-lo como sua opção "confiável".

Você não pode usar \0 em variáveis ​​de ambiente, então seria difícil exportar arrays para shells filhos.

Estou migrando do zsh, onde uso esta sequência para definir o $LESS env var de maneira sensata, aproveitando seu recurso de variáveis ​​"vinculadas":

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

Eu omiti a lista completa de opções por brevidade. Em zsh, isso resulta em $LESS env var sendo uma lista separada por espaços das opções na matriz $less. O equivalente em fish resulta na separação dos elementos pelo caractere separador de registro (\x1e). Apesar da documentação dizer que os elementos do array serão separados por espaços (módulo os arrays especiais como PATH). Eu tenho que fazer explicitamente uma atribuição que interpola os valores em uma única string para obter o resultado esperado:

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

No momento, não me importo se \x1e é usado internamente para serializar arrays em vez de \x00. Eu me importo que os arrays exportados tenham seus elementos separados por \x1e. Isso é apenas quebrado, errado, fubar. Escolha o seu adjetivo. Também é inconsistente com a solução alternativa e o comportamento documentado mencionados acima. Este problema deve ser marcado como um bug IMHO.

PS, Em nenhum lugar da documentação é mencionado o uso do caractere separador de registro (\x1e). O que é outro problema.

@krader1961 Obrigado por compartilhar isso. Não há convenção Unix padrão para variáveis ​​de ambiente do tipo lista - algumas são delimitadas por dois pontos, outras são delimitadas por espaço. fish usa \x1e para poder distinguir seus próprios arrays.

Você pode nos apontar a documentação errônea?

Como você acha que os arrays são exportados - dois pontos, espaços, novas linhas, algo mais? Fish deve tokenizar variáveis ​​de ambiente neste personagem também?

Parece que menos espera argumentos delimitados por espaço. Provavelmente a solução mais simples é set -x LESS '--HILITE-UNREAD --LONG-PROMPT' , etc.

Não há um padrão para variáveis ​​de ambiente de lista porque, por definição, elas são uma sequência arbitrária de bytes composta por uma chave e um valor separados por um sinal de igual e terminado por um byte nulo. Eles nem precisam ser caracteres imprimíveis. A única convenção amplamente aceita para um nível mais alto de abstração é aquela estabelecida pela função execlp() para o PATH env var.

A documentação é errônea na medida em que não menciona o uso de \x1E, \036, 30 ou o caractere "separador de registro" para separar elementos de um array ao exportar um var com mais de um elemento. A documentação afirma que

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

Isso é da seção "Expansão de variável" em http://fishshell.com/docs/current/index.html. É razoável inferir que essa declaração também se aplica a vars exportados que não são maiúsculas e minúsculas conforme documentado nas seções "Arrays" e "Variáveis ​​especiais" desse mesmo documento.

É meu sentimento que fish não deve automaticamente tokenizar env vars em uma lista fora das vars de caso especial delimitadas por dois pontos, como PATH. No entanto, deve haver um meio robusto pelo qual um usuário possa tokenizar um var em uma matriz em um caractere arbitrário.

Na ausência de um mecanismo para configurar o caractere a ser usado var por var (além do comando zsh "typeset -T") um espaço deve ser usado ao concatenar os elementos do array (novamente, excluindo os vars de caso especial separados por dois pontos ). Obviamente, isso não se aplica a armazenamentos de dados privados, como o armazenamento de variáveis ​​universais.

Por fim, não consegui encontrar nenhum uso nas funções fish padrão onde um env var é usado para passar uma matriz contendo mais de um elemento para outra função ou script. Esses casos de uso podem existir, mas devem exigir que os scripts cooperem explicitamente na serialização/desserialização dos dados, em vez de depender de fish para reconstruir implicitamente arrays de vars cujas strings contêm o caractere separador de registro.

Obrigado pela sua resposta pensativa. A seção que você citou sobre concatenação usando espaço é especificamente para strings com aspas duplas. Devemos adicionar alguma discussão sobre o que acontece com arrays exportados.

Os usuários podem tokenizar strings com, por exemplo set SOMEPATH (string split : $SOMEPATH) .

A desvantagem das variáveis ​​exportadas com concatenação de espaço é que elas são alteradas quando o fish é executado recursivamente. Hoje isso funciona:

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

Mas se exportássemos com espaços, isso mostraria 1 para a chamada recursiva. Como você disse, não dependemos disso, mas é bom do ponto de vista da consistência.

Obrigado pela sua resposta pensativa.

Vou ter que segundo isso! Sempre bom ter uma nova perspectiva sobre as coisas.

Para os novos nesta discussão, acho que terei que trazer algumas coisas relacionadas a isso.

O que vem à mente imediatamente é a lista branca do listify , que aparece em questões como #2090.

Isso significa que para $PATH, $CDPATH e $MANPATH, eles aparecerão como listas/arrays para pescar, mas quando exportados, serão unidos com ":" novamente. Então, um peixe dentro de um peixe os dividirá novamente. Isso opera em dois pontos, não em \x1e. Do meu entendimento do código , parece fazê-lo em todos os dois pontos, sem chance de escapar, portanto, pode quebrar as entradas $ PATH com dois pontos dentro delas - o que o UNIX permite dentro de caminhos de arquivo, embora pareça quebrado para $ PATH pelo menos . Este esquema também é usado para, por exemplo, PYTHONPATH e GOPATH.

Eu adoraria ter algo um pouco mais explícito para dividir variáveis ​​de ambiente do que o sempre-split-on-\x1e-except-for-these-three-split-on-colon implícito, porque na verdade são dois esquemas diferentes em one e exportar uma lista atualmente sempre confundirá tudo, exceto peixes.

Minha solução preferida seria uma função como 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

(Se string split tivesse superpoderes , isso seria um pouco mais simples)

Todas as listas seriam unidas com dois pontos quando exportadas, para que um usuário possa desassociá-las explicitamente com splitenv (embora eu não esteja definido em uma função auxiliar, acredito que tornar isso trivial é uma boa coisa para fazer). Para compatibilidade com versões anteriores, splitenv PATH CDPATH MANPATH seria executado na inicialização. Se um usuário desejar exportá-lo de forma diferente, string join está disponível.

Tudo isso significa que não precisamos mais de \x1e, temos um esquema que pelo menos tem uma chance de ser entendido por outros programas, mas o (um tanto exótico IMHO) peixe-dentro-peixe agora se torna fish -c 'splitenv list; count $list' .

O problema é que, como mencionado, o esquema usual de lista separada por dois pontos não tem como escapar de dois pontos, e se quisermos adicionar um, string split não tem um "--unescaped" opção para dividir apenas em separadores sem escape.

Estou fazendo algum sentido?

@faho Acho que essa ideia tem mérito. A pior parte do esquema antigo era dividir implicitamente em dois pontos, o que desmontaria variáveis ​​que não deveriam ser divididas. Na sua ideia isso é (quase) sempre explícito, então acho que é bastante seguro.

Em relação ao escape, não o escape de dois pontos no PATH é intencional de acordo com o link que você encontrou. Duvido que PYTHONPATH, CLASSPATH, etc. sejam mais consistentes a esse respeito. Como você não pode usar dois pontos nesses caminhos, podemos escolher se vamos ou não escapar; mas se escaparmos de dois pontos, precisamos escapar de barras invertidas, e aposto que você pode ter uma barra invertida em PATH. Podemos precisar de uma lista branca "não escape" (ugh).

Alternativamente, não nos preocupamos com isso e apenas deixamos qualquer dois-pontos atuar como delimitador. Acho que me inclino para isso pela simplicidade e familiaridade com outros shells.

Ainda nos deparamos com o problema de que algumas variáveis ​​do tipo lista são delimitadas por espaço e outras são delimitadas por dois pontos. Uma possibilidade é que splitenv aceite um delimitador, lembre-se dele e o use para reconstruir o valor na exportação:

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

Essas chamadas agora desempenham o papel duplo de importar qualquer variável existente e marcar como ela é exportada. O que você acha?

Além disso, existe uma maneira de fazer isso sem editar config.fish? Talvez como parte de variáveis ​​universais?

Ainda nos deparamos com o problema de que algumas variáveis ​​do tipo lista são delimitadas por espaço e outras são delimitadas por dois pontos. Uma possibilidade é que splitenv aceite um delimitador, lembre-se dele e o use para reconstruir o valor na exportação:

Parece bom. Embora nesse ponto fazer splitenv um script provavelmente não ajudaria, já que precisaríamos de cooperação do lado C++ de qualquer maneira.

Essas chamadas agora desempenham o papel duplo de importar qualquer variável existente e marcar como ela é exportada.

É possível que agora "splitenv" não seja mais o nome perfeito (era quando eu pensei nisso, é claro :laughing: ) - Eu também considerei "listify".

Embora esteja me incomodando não me lembrar de onde tivemos uma discussão relacionada antes - acho que vou precisar vasculhar os problemas novamente esta noite.

Os usuários podem tokenizar strings com, por exemplo set SOMEPATH (string split : $SOMEPATH) .

O comando string não está documentado em nenhum lugar que eu possa encontrar. Além disso, man string mostra a página de manual string(3) que documenta as funções de manipulação de strings no BSD (e Mac OS X).

Mas se exportássemos com espaços, isso mostraria 1 para a chamada recursiva. Como você disse, não dependemos disso, mas é bom do ponto de vista da consistência.

Esse comportamento é, no entanto, surpreendente. Estou disposto a apostar que se você perguntar a 100 pessoas o que acontece quando um var com mais de um elemento é exportado, 90 deles dirão que os valores estão concatenados com espaço como separador. Alguns podem dizer que vírgula ou outro caractere é usado como separador. E as duas pessoas que executaram env dirão que os valores são concatenados sem separador porque, a menos que você filtre a saída por algo como cat -evt o caractere separador de registro é invisível.

que aparece em edições como #2090

Desculpe, mas não vejo nenhum mérito na reclamação desse usuário. O problema é contornado de maneira trivial testando explicitamente se MANPATH já está definido. O que, parece-me, é algo que você tem que fazer em qualquer caso, dada a semântica de dois pontos iniciais versus dois pontos finais.

para que possa quebrar nas entradas $ PATH com dois pontos dentro delas

É pelo menos trinta anos tarde demais para consertar isso. Não devemos implementar o escape de dois pontos (e, por extensão, o caractere de escape), pois isso seria um comportamento fora do padrão. Até recentemente, passei mais de 20 anos como especialista em suporte ao UNIX. Eu nunca ouvi alguém reclamar que a presença de dois pontos em um diretório embutido em $ PATH ou uma variável semelhante era um problema.

Minha solução preferida seria uma função como splitenv var1 var2 var3

Tudo bem, embora não esteja claro por que o (não documentado) string split não é suficiente. Independentemente de precisarmos de uma nova função, definitivamente não devemos adicionar novas vars env de divisão automática. Os únicos dois que são comuns o suficiente para garantir esse comportamento são PATH e CDPATH (e MANPATH, pois já é especial). Outras vars como PYTHONPATH podem ser explicitamente divididas por um usuário se acharem útil.

No entanto, dito que certamente deve haver uma maneira de registrar que uma determinada var (por exemplo, PYTHONPATH) deve ter seus elementos concatenados com um separador char específico ao ser exportado. A maneira mais natural de fazer isso é através de uma nova opção para o comando set . Por exemplo,

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

Isso não afetaria como o var é armazenado no armazenamento de dados universal var onde o caractere separador de registro ainda seria usado e seria dividido automaticamente quando carregado desse armazenamento de dados. A ser determinado é se o caractere separador registrado para exportação também deve afetar a interpolação de string. Minha sensação é que deveria. Ou seja, se o comando "set" acima for executado, um

echo "PYTHONPATH is $PYTHONPATH"

deve usar dois pontos em vez de um espaço para concatenar os valores de PYTHONPATH. O separador padrão é um espaço para preservar a semântica existente e minimizar a surpresa para o usuário. Observe que as vars com maiúsculas e minúsculas como PATH também usariam dois pontos nesse exemplo. O que é incompatível com o comportamento atual, mas é consistente com a nova semântica e menos surpreendente. Em outras palavras, por que os elementos de $PATH são separados por dois pontos no ambiente exportado, mas espaços na saída de

echo "PATH is $PATH"

O comando string não está documentado em nenhum lugar que eu possa encontrar. Além disso, man string mostra a página man string(3) que documenta as funções de manipulação de strings no BSD (e Mac OS X).

Tigre facil. Está nas versões de desenvolvimento - veja https://github.com/fish-shell/fish-shell/blob/master/doc_src/string.txt

Tudo bem, embora não esteja claro por que a divisão de strings (não documentada) não é suficiente.

Minha ideia original era que é uma função de conveniência, então essa operação se torna completamente trivial. Com a proposta do @ridiculousfish ele se torna algo mais e ajusta algum tipo de loja para que a variável também seja juntada nesse personagem quando exportado. string split é apenas um comando que divide uma string - basicamente nossa versão de cut .

A maneira mais natural de fazer isso é através de uma nova opção para o comando set.

Essa é outra opção, embora eu não esteja completamente convencido da semântica. Por exemplo set -S ':' PYTHONPATH . Isso definiria PYTHONPATH para a lista vazia ou apenas dividiria o PYTHONPATH existente? Até agora, todas as opções definidas fizeram o primeiro, então você teria que fazer set -S ':' PYTHONPATH $PYTHONPATH . Ou faríamos isso _não_ fazer isso e ter inconsistência dentro da mesma ferramenta.

Em outras palavras, por que os elementos de $PATH são separados por dois pontos no ambiente exportado, mas espaços na saída de echo "PATH is $PATH"

Essa é realmente uma boa pergunta. É claro que você não esperaria que o separador aparecesse em for p in $PATH; echo $p; end , mas juntá-lo com o separador por variável char pode ser a coisa certa a fazer. Claro que há string join para fazer isso manualmente.

Esse comportamento é, no entanto, surpreendente. Estou disposto a apostar que se você perguntar a 100 pessoas o que acontece quando um var com mais de um elemento é exportado, 90 deles dirão que os valores estão concatenados com espaço como separador.

Há um problema geral em fazer design-por-pesquisa e pescar. Porque as pessoas pesquisadas frequentemente têm conhecimento de bash (e, em menor grau, outras conchas POSIXy), enquanto a própria ideia de peixe é fazer algo _melhor_ abandonando pelo menos parte do POSIX.

Isso não quer dizer que seja completamente inútil, é apenas algo para se ter em mente - se nos apegássemos a esse tipo de ideia, teríamos o comportamento de divisão de palavras do bash e if-fi.

set -S ':' PYTHONPATH definiria PYTHONPATH para a lista vazia ou apenas dividiria o PYTHONPATH existente?

Seria defini-lo para uma lista vazia. Se o usuário quiser manter o valor existente, ele deve incluí-lo explicitamente (veja abaixo).

Já temos todos os recursos necessários, com exceção de um meio de configurar o caractere (ou a string vazia) a ser usado ao concatenar elementos de array de uma determinada var para exportação ou interpolação. Se alguém quiser manipular um var como PYTHONPATH, poderá tratá-lo como uma string simples:

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

Ou eles podem tratá-lo como uma matriz:

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

Observe que minha proposta de usar o caractere de divisão/concatenação em vez de um espaço ao interpolar em uma string fornece um comportamento consistente, independentemente de o usuário dividir ou não o var em uma matriz.

Definitivamente, não estou sugerindo design por comitê. Dessa forma, encontra-se loucura e bogosities como zsh. Estou simplesmente apontando que, quando dadas duas ou mais opções sem outro motivo para escolher uma em vez da outra, escolher a opção que menos surpreenderá um usuário do shell é a melhor escolha. É também por isso que me oponho (no momento) à introdução de novos comandos ou comportamentos, como vars de divisão automática (além de PATH e CDPATH, é claro). Este é o tipo de coisa que é feita com pouca frequência e geralmente apenas no config.fish e em algumas funções especializadas como o script "activate" do Anaconda. E a maneira de fazer com que o último se comporte corretamente, independentemente de o usuário já ter dividido o var em um array em seu config.fish, é sempre tratá-lo como uma string que precisa ser dividida. Por exemplo, se o PYTHONPATH precisar ser alterado, ele poderá fazer algo assim:

# 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

Ou, mais simplesmente,

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

Sim, isso potencialmente transforma o que pode ter sido uma simples string em uma matriz. Mas com minha regra de que o caractere especificado pelo switch -S é usado ao exportar e interpolar essa conversão em uma matriz não deve importar na prática. Há, no entanto, um caso de canto. O que acontece se o usuário não converteu explicitamente o var em um array em seu config.fish e então executa algo como o script hipotético acima. O var potencialmente se torna uma matriz de vários elementos, o que significa que, se eles fizerem

for elem in $PYTHONPATH
   echo $elem
end

Isso não executará o corpo do loop for apenas uma vez com o valor na forma de diretórios separados por dois pontos, como o usuário poderia esperar, pois não sabia da divisão feita pelo script hipotético "activate". Acho que podemos conviver com isso, pois seria perverso um usuário fazer algo assim.

tl; dr Eu acho que as listas devem "lembrar" seu delimitador e abaixo está o porquê.


Concordo com muito do que foi dito acima. Uma coisa que ainda parece tediosa é que os comandos acima ainda parecem excessivamente detalhados; ou seja, às vezes é mais simples descrever alguns desses comandos em inglês simples.

Como exemplo (e não estou focando tanto no comprimento quanto no número de coisas repetidas):

  • peixe: set -S ':' PYTHONPATH /activated/python/tree (string split ':' $PYTHONPATH)
  • Português: "anexar /activated/python/tree a PYTHONPATH ( : -delimited`)"

Há duas coisas repetidas aqui: PYTHONPATH e o delimitador : . Que PYTHONPATH deve ser repetido é indiscutivelmente correto por dois motivos, e nenhum desses dois motivos se aplica ao delimitador.

  1. Não é difícil intuir o que está acontecendo quando alguém diz set PYTHONPATH /activated/python/tree $PYTHONPATH , porque isso é muito parecido com coisas como i = 2 + i , que é um conceito/idioma muito familiar. (Mas ainda temos atalhos como += , e é por isso que proponho o sinalizador --append abaixo.) Por outro lado, quando as pessoas pensam em anexar a uma lista, elas não pensam em dividir e juntando em um delimitador. Eles não pensam em converter a lista inteira para algum outro formato, fazer a operação real e colocá-la de volta. Em sua mente, eles naturalmente leem o delimitador como um delimitador em vez de alterá-lo para algum delimitador "interno" ou "preferido".
  2. Usar um comando simples set para anexar salva a adição de outro comando para juntar duas listas diferentes. Por outro lado, converter de um delimitador para outro é algo que idealmente nunca queremos que o usuário faça manualmente, principalmente pelo motivo acima.

Em contraste, sugiro outra maneira de especificar o delimitador nas listas: associá-lo à lista indefinidamente. Assim, o exemplo acima pode ser feito da seguinte forma:

# 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

Implicações/perguntas de acompanhamento/etc:

  1. Isso é bastante compatível com a sugestão atual. Aqui estão as alterações necessárias:

    • Faça o delimitador ficar (possivelmente usando outra variável como __fish_sep_PYTHONPATH )

    • (opcional) Adicione um sinalizador que estou chamando atualmente --no-modify , que diz ao fish para alterar o delimitador de uma lista sem alterar seu conteúdo. Possivelmente também adicione os sinalizadores --append e --prepend por causa do motivo (1) acima. De qualquer forma, este não é necessário, como mostra a solução alternativa acima, à la como anexar e preceder são feitos em peixes hoje.

  2. Nos peixes, as listas devem pelo menos _ser tratadas_ como cidadãos de primeira classe. Isso significa que alterar o delimitador deve alterar a representação da string, não a representação da lista (a menos que o delimitador esteja presente em um dos elementos, caso em que a divisão é inevitável). Por exemplo, se você estiver alterando os delimitadores de , para : , ["0:1", "2"] deve se tornar ["0", "1", "2"] e não ["0", "1,2"] (que é o que aconteceria se você simplesmente alterasse o delimitador sem alterar a string que sustenta a lista). Esse comportamento deve maximizar a compatibilidade com o comportamento atual e o fato de que atualmente existe um delimitador padrão imutável.

Aqui está a linha de fundo:

  • Isso envolve muito menos tokens e quase nada é repetido.
  • Isso é paralelo ao modelo mental que muitos usuários têm. Os usuários pensam nestes termos: "prepend", "defina o delimitador", "não modifique".
  • Essa parece ser a única maneira certa de fazer essa tarefa (a maneira antiga agora parece mais desajeitada) e, portanto, essas adições não destroem a ortogonalidade.
set --no-modify -S : PYTHONPATH
set --prepend PYTHONPATH /activated/python/tree

Obrigado, @szhu , pelo comentário detalhado sobre minha proposta. No entanto, há muitos problemas com a solução proposta. Por exemplo, a adição da opção --no-modify de fato modifica a variável convertendo-a em uma lista e, portanto, modifica a variável. Embora eu rejeite quase todos os elementos de sua proposta, isso me fez pensar em uma solução mais direta que abordaria a maioria, se não todos, de seus pontos. Talvez devesse haver um mecanismo para dizer aos fishes que um determinado env var deve sempre ser automaticamente dividido e reconstituído em um determinado token (por exemplo, ":" ou " "). Isso pode ser chamado de designação de matriz automática e, quando executado, qualquer valor existente será imediatamente dividido se ainda não for uma matriz.

Uma nova opção pode ser adicionada ao comando set para ativar este comportamento. No entanto, estou preocupado que isso seja ambíguo e possa ser interpretado como a definição de uma variável sem valor. Adicionar uma opção de token -A ao comando set não seria ambíguo? Por exemplo:

set -x -A ':' PYTHONPATH

Presumivelmente, isso converteria imediatamente qualquer PYTHONPATH env var existente em uma matriz depois de ser dividido em dois pontos. Inversamente, resultaria na concatenação dos valores em dois pontos quando exportados ou interpolados em uma string. Da mesma forma, mesmo que PYTHONPATH não existisse no momento em que o comando fosse executado, a especificação de matriz automática seria lembrada e os usos subsequentes seriam afetados. Por exemplo, isso obviamente criaria uma matriz:

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

Mas e o último argumento? Deve ser dividido automaticamente em dois tokens?

Observe que esse comportamento deve se aplicar apenas a vars exportados e um erro seria gerado de outra forma. Há também alguns casos de canto que precisam ser explicados. Por exemplo, e se a declaração de divisão automática original incluir valores como neste exemplo:

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

Esses valores devem ser divididos no token de divisão automática? Ou deve resultar em um erro e exigir que a modificação do valor seja feita em uma instrução separada? E qualquer que seja a sintaxe escolhida, você ainda tem o problema do que fazer com os valores que contêm o token de divisão automática. O diabo está nos detalhes. O que quer dizer que pode haver outras ramificações desta proposta que eu não pensei. Minha proposta original com uma sintaxe mais detalhada evita esses problemas até onde posso dizer.

@krader1961 , obrigado pela sua resposta. No entanto, você parece pensar que estou convertendo variáveis ​​de strings para listas. Acho que você está entendendo mal um conceito importante em fish: cada variável é uma lista de strings . As variáveis ​​que parecem ser strings são, na verdade, listas de comprimento 1. O fish as trata de maneira não diferente de listas de comprimento 0 ou 2 ou qualquer outro comprimento.

Além disso, observe que, embora a string subjacente usada para transmitir variáveis ​​de ambiente possa mudar quando você altera os delimitadores, um dos pontos fortes do fish é que o usuário normalmente não precisa pensar em delimitadores. É por isso que eu recomendo que tudo que a opção -S faça seja especificar como essa lista deve ser convertida em uma string quando ela for _exportada para fora_ do peixe. -S não deve alterar a representação da lista no peixe (exceto nos casos em que é impossível representar essa lista usando o delimitador de destino).

A propósito, aqui está um exemplo que mostra como minha proposta é limpa. Aqui está o código para converter uma variável $L de volta ao delimitador padrão de \x1e . Ele não terá absolutamente nenhum efeito em qualquer variável (qualquer escopo, qualquer número de itens) que possa ser criado no peixe hoje.

set -S \x1e L $L

Mais uma coisa: a família de argumentos --no-modify são apenas atalhos. Aqui estão seus equivalentes:

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

(Afirmei o seguinte antes, mas acho que posso fazer um trabalho melhor explicando-o agora.) Ao enfatizar como esses três argumentos são "burros", alguns podem questionar se eles são necessários. Pode-se citar que o peixe tem um princípio de design de ortogonalidade . Quando todas as coisas são ortogonais, isso significa que, para qualquer grande tarefa que você deseja fazer, deve ser óbvio qual conjunto de recursos escolher para fazer essa tarefa - deve haver apenas uma maneira correta de fazê-lo. Aqui, eu realmente adiciono outra maneira de anexar/anexar a/evitar modificações em uma lista, mas isso ocorre apenas porque acho que os equivalentes que estão sendo substituídos são desnecessariamente detalhados; eles não devem ser as maneiras corretas de anexar listas de modificação. Uma maneira de se convencer disso é pensar em como você pensa em anexar a uma lista. Você provavelmente pensa "anexar $TOADD a $L " em vez de "definir $L a $L $TOADD ".

Deixe-me saber o que você pensa, e se isso for um caso mais convincente para minha proposta. (Também é muito comum eu não entender as coisas, então sinta-se à vontade para me corrigir.)

@szhu Estou ciente de que todos os vars em fish são listas de zero, um ou mais valores. Você também aparentemente não leu meus comentários anteriores, onde afirmo claramente que o delimitador associado não deve afetar a representação interna ou como os valores são persistidos no armazenamento de dados universal (além de armazenar o delimitador). Você também não abordou meus pontos anteriores. Considere seu último exemplo:

set -S \x1e L $L

O que isso deveria fazer se L já contiver dois ou mais valores? Presumivelmente, nada além de alterar o delimitador associado. O argumento $L seria opcional nesse caso? Ou deve primeiro converter a matriz existente em uma string simples (presumivelmente concatenando usando o delimitador existente) e depois dividir essa string no novo delimitador? Como eu disse antes, o diabo está nos detalhes.

Em última análise, os designers e mantenedores estabelecidos decidirão se sua família de funções --no-modify deve ou não ser adicionada, mas eu voto não, pois eles não agregam valor suficiente em minha opinião em relação ao custo.

Desculpe, este tópico é longo, devo ter perdido o seu reconhecimento sobre isso acima; bom saber que estamos na mesma página! Acho que abordei a maioria de suas preocupações acima também, mas não todas. Abordarei especificamente cada uma de suas preocupações abaixo.


1. O $L é opcional em set -S \x1e L $L ?

O comportamento existente de set não será alterado. Sob o comportamento atual, set L $L não muda L e set L torna L uma lista vazia. O mesmo com set -S \x1e L $L e set -S \x1e L .

1.1 set -S \x1e L $L não parece excessivamente detalhado para apenas alterar o delimitador?

Levemente. É por isso que proponho a opção --no-modify como um atalho para isso.

Mas meu plano não vai desmoronar se esse atalho não existir. Já lidamos com esse problema todos os dias quando anexamos listas: set PATH ~/.bin $PATH . Por isso, pelo mesmo motivo, proponho --prepend e --append também.

2. Como seria o processo de conversão?

Digamos que nosso delimitador antigo seja \x1e e nosso novo seja : , e que tenhamos uma lista de peixes ["hello", "world"] (exportada como hello\x1eworld ). Existem duas maneiras básicas de fazer a conversão (" opções de conversão "):

  1. Use ["hello", "world"] e converta para ["hello", "world"] (exportado como hello,world )
    Vantagem: A representação da lista não muda.
  2. Use hello\x1eworld e converta para ["hello\x1eworld"] (exportado como hello\x1eworld )
    Vantagem: A representação do valor exportado não muda.

Observe que isso é de uma perspectiva de interface do usuário, não de uma perspectiva de implementação; estamos falando sobre o que parece para o usuário. Abordarei a implementação na próxima pergunta. _Observação: o restante desta resposta é um material novo que não abordei acima, motivado por suas perguntas. Obrigado!_

Dentro dos peixes. Primeiro, se estamos trabalhando inteiramente em fish, as listas são de primeira classe e você nunca deve se preocupar com delimitadores e, portanto, nenhum deles é obrigatório. (Mais uma vez, "deveria" é da perspectiva do usuário, como desenvolvedores, é nossa responsabilidade tornar isso verdade.)

Alterando o formato de exportação de vars. Assim, a única razão pela qual um usuário precisará alterar os delimitadores é alterar a string exportada para programas que lêem variáveis ​​de ambiente. Para listas que são criadas em fish, definitivamente usaremos a opção de conversão 1 , pois o significado da variável como lista é importante e bem definido, por isso precisamos preservar a representação da lista.

Alterando o formato de importação de vars. No entanto, para variáveis ​​de ambiente como PATH que são inicialmente criadas fora do fish, precisamos, para uma lista que já tem um delimitador, dizer ao fish qual é esse delimitador. Para isso, podemos usar a opção de conversão 2 .

2.1 Como isso seria implementado?

Fish mesmo que o usuário não precise saber disso, fish na verdade armazena listas como strings. A variável x é armazenada como hello\x1eworld . Na minha proposta, haveria outra variável, __fish_delimiter_x , que especifica o delimitador da variável x . Ele não existe no momento e por isso usamos o delimitador padrão, \x1e .

Para a opção de conversão 1:

  1. Divida a variável no delimitador antigo, resultando em uma lista verdadeira na linguagem de implementação (C++).
  2. Junte-se à lista usando o novo delimitador, resultando em uma nova string.
  3. Salve o novo delimitador em __fish_delimiter_x .

Para a opção de conversão 1, uma implementação equivalente:

  1. Na variável, substitua todas as ocorrências do delimitador antigo pelo novo.
  2. Salve o novo delimitador em __fish_delimiter_x .

Para a opção de conversão 2:

  1. Salve o novo delimitador em __fish_delimiter_x .

2.2 Se precisarmos das duas opções de conversão, como o usuário especificaria qual usar?

Talvez possamos ter duas opções: -D ou --convert-delimiter para a opção 1 e -d ou --set-delimiter para a opção 2.

2.3 Precisamos mesmo das duas opções?

Sob os peixes atuais, optamos por assumir que não veremos \x1e na natureza fora dos peixes. Se mantivermos isso como o delimitador padrão e mantermos essa suposição, a opção de conversão 1 será suficiente para converter e definir o delimitador e não precisaremos da opção de conversão 2 . (Uma maneira fácil de se convencer disso é perceber que se a suposição for verdadeira, ao converter listas criadas externamente, o passo da opção de conversão 1 "substituir todas as ocorrências do delimitador antigo pelo novo" não fará nada, reduzindo toda a conversão para a opção de conversão 2.)


@ridiculousfish , gostaria de receber seu feedback sobre isso também, especificamente em relação à interface do usuário e aos detalhes de implementação. Obrigado!

Parece que há dois problemas aqui. Vamos falar sobre o primeiro?

+1 para matriz verdadeira

Esse truque do separador é realmente necessário para os peixes? Ping #627

Revisitando isso à luz da minha correção para o problema nº 2106, no qual notei que havia duas maneiras incompatíveis de converter a representação de string para valores de variáveis ​​em matrizes. Um dos quais eliminou incorretamente elementos vazios. A questão central é que class env_var_t é baseado em wcstring em vez de um vetor de wcstring. Se vale a pena ou não mudar isso, o esforço está aberto para debate.

Se você está acompanhando esta edição, eu o encorajo a dar uma olhada, e talvez testar, PR #4082. Decidi que a melhor maneira de resolver isso é com variáveis ​​"vinculadas" semelhantes ao recurso com o mesmo nome em zsh.

Parece que as questões em torno dessas listas exportadas por dois pontos e quais envvars devem ser incluídas nesta lista branca é algo ainda indeciso. Qual é a situação atual sobre este assunto? Podemos esperar uma solução final para este tópico? Ainda hoje, novamente me deparo com a armadilha de que LD_LIBRARY_PATH não está na lista de permissões ...

Para resumir: as variáveis ​​de ambiente Unix são strings, então env vars do tipo array devem usar um delimitador. A maioria usa dois pontos ($PATH); embora nem todos o façam ($LESS). Gostaríamos de usar apenas dois pontos para delimitar todos os arrays na importação/exportação (e, de fato, os peixes costumavam funcionar dessa maneira); o problema é que algumas variáveis ​​simples contêm dois pontos ($DISPLAY, $SSH_CONNECTION).

O objetivo é fazer com que as variáveis ​​delimitadas funcionem naturalmente com o suporte de array do fish. @szhu sugeriu aprimorar set para rastrear um delimitador, mas o aprimoramento da IMO set é o lugar errado para anexar isso:

  • Interação irritante entre definir a variável e definir seu delimitador (motivando --no-modify ).
  • Perguntas complicadas sobre como os delimitadores interagem com o escopo variável.
  • Problemas em torno de variáveis ​​universais. Teríamos que ensinar uvars a lembrar o delimitador, e também --no-modify já que não há como definir uma variável para seu valor atual com uvars.

Na revisão, sou a favor da ideia splitenv de @faho . splitenv name dividiria a variável existente em dois pontos, é isso. É maravilhosamente simples. Variáveis ​​que não usam dois pontos são raras o suficiente para que não precisemos de suporte especial para elas.

A desvantagem é que os arrays exportados de peixe seriam reimportados como uma string delimitada por dois pontos; na prática, acho que isso será raro.

Não devemos infligir essa complicação splitenv aos usuários se pudermos evitá-la. Então, eu quero ir um passo além e expandir a lista branca de dois pontos para todas as variáveis ​​de ambiente cujo nome termina em PATH , por exemplo, LD_LIBRARY_PATH, PYTHONPATH, etc. Na prática, isso deve fazer a coisa certa quase o tempo todo; qualquer um mordido por ele pode usar string join para corrigir o valor.

Então o que eu proponho (realmente a proposta do faho):

  • Exporte todos os arrays usando dois pontos; não há mais separador de registro ASCII.
  • Implemente uma função splitenv que divide uma variável em dois pontos. Isso pode ser escrito em script de peixe.
  • Aprimore a lista branca separada por dois pontos para todas as variáveis ​​que terminam em PATH.

Acredito que isso resolverá a maior parte da dor associada a matrizes delimitadas por dois pontos de maneira minimalista e compatível.

sobre a ideia splitenv:

Digamos que eu queira que o peixe exporte uma lista cujos itens contenham dois pontos, por exemplo: ["item1", "item:2"] . (Eu não acho que isso seja uma ocorrência rara, especialmente quando matrizes são usadas para armazenar a entrada do usuário.)

A lista será exportada como item1:item:2 ? Nesse caso, será impossível recriar a lista original após a exportação.

Além disso, ter uma lista branca imutável para variáveis ​​parece errado, embora ter a lista branca *?PATH pareça menos errado. (Essa foi outra razão para minha proposta de armazenar o delimitador como uma variável - a lista branca pode ser alterada definindo uma variável.)

@szhu Você está certo. Exported-lists-can't-contain-colons é um problema que o Unix já sofre :

Desde \

então não me sinto muito mal em introduzir a mesma limitação para peixes (apenas para variáveis ​​exportadas).

Além disso, esse problema ocorre apenas ao exportar uma matriz para uma instância de peixe invocada recursivamente, o que acho que será raro. Se isso for comum, podemos anexar dados sidecar em outra variável ou usar um separador de array diferente ao invocar fish recursivamente. Meu palpite é que não precisaremos ir tão longe.

Concordo que o caso extremo em que a proposta não funciona bem não é muito comum, mas temo que seria muito ruim se as pessoas se deparassem com isso.

Aqui está um exemplo que é apenas parcialmente inventado:

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

Posso imaginar muitos novos usuários confusos depois de observar o que foi dito acima.

Eu acho que o seguinte comportamento seria significativamente mais agradável:

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

Gostaria da opinião de vocês e da comunidade sobre isso.

Por que não escapar dos dois pontos existentes? Isso preservaria a distinção.

Escapar faz sentido para mim.

Ainda pode ser confuso se uma variável é uma matriz não ser lembrada?

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

sim. Minha hipótese é que exportar arrays não é comum, fora das listas de caminhos.

MANPATH tem um significado especial para dois-pontos duplos (::) - veja #2090 - isso atrapalha o funcionamento?

Eu também argumentaria que ter uma variável sidecar FISH_ARRAY_VARIABLES=FOO\t:\nBAR\t;\nBAZ\t-\n em qualquer caso seria uma boa dica para instâncias de Fish sendo invocadas para pegar as variáveis ​​de array novamente, sem perturbar outros processos e sem exigir um "nós estamos envolvendo peixe agora" verificador ..

re: https://github.com/fish-shell/fish-shell/issues/436#issuecomment -392409659 @zanchey
Eu não li o nº 2090 em detalhes, mas acredito que a conversão entre a string delimitada por dois pontos e os formulários de matriz é completamente perfeita (exceto quando dois pontos ~não aparecem~ aparecem em itens de matriz).

Para incluir dois-pontos duplos em MANPATH , basta adicionar uma string vazia onde os dois-pontos duplos devem aparecer:

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

Para começar MANPATH com dois pontos, basta adicionar um item de string vazio no início:

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

Não acompanhei tudo aqui, mas como usuário quero defender "sem configuração".
Acho que set -S e splitenv são formas de configuração. Alguns usuários fariam isso no fish.config e tratariam PYTHONPATH como array. Outros não aceitariam e tratariam PYTHONPATH como uma palavra delimitada por dois pontos. Copiar e colar conselhos de stackoverflow e executar scripts manipulando PYTHONPATH de um usuário para outro nem sempre funcionaria ...

Uma regra fixa "se terminar com PATH " não tem configuração e soa tão perfeita quanto você pode obter :+1:
(Eu não tenho opinião sobre se vale a pena a incompatibilidade com versões anteriores)
Sim, set -x TEST2_PATH color:red font:serif seria importado como color red font serif array, mas esse é o negócio com a exportação de variáveis. Você não pode realmente definir um var exportado para um array sem entender como ele funciona.

sim. Minha hipótese é que exportar arrays não é comum, fora das listas de caminhos.

@ridiculousfish isso pode ser verdade em conchas atuais, mas imagino que à medida que o peixe ganha mais tração, os usuários podem querer aproveitar a capacidade do peixe de enviar listas para conchas de peixe filho. Eu posso imaginar que pode eventualmente haver programas/plugins que gerenciem o estado de uma sessão de fish (vou verificar este comentário em alguns anos para ver se isso é verdade), e ser capaz de auto-des/serializar listas universalmente tornará esse código mais limpo e menos alternativo.


Um pensamento semelhante, mas um pouco diferente: Tratar PATH como um caso especial é um caso extremo anacrônico que os usuários provavelmente entenderão apenas se tiverem um histórico em casos de uso típicos de shells. Isso limita a capacidade do fish de ser usado como uma linguagem de script geral e limita alguns casos de uso futuros em potencial.

@ridiculousfish Acho que uma solução possível é associar cada variável/array de ambiente com seu próprio separador (e você pode manter '\x1e' ou ' ' ou ':' como padrão), e o usuário que cria a variável de ambiente é responsável por escolher os separadores apropriados para evitar conflitos. O comando pode ser: set --separator ':' TMP 1 2 3 . Assim, para essas variáveis ​​de ambiente conhecidas, os usuários podem apenas escolher os separadores conhecidos correspondentes que também podem ser reconhecidos por outros programas e podem tornar o peixe mais compatível com mais programas (como Python).

Para aqueles que estão apenas lendo comentários recentes, apenas uma observação de que a recomendação set --separator de @thuzhf é a mesma que a recomendação set -S mencionada repetidamente ao longo deste tópico. Para obter mais contexto sobre essa discussão, você pode grep esta página por set -S .

@szhu Desculpe por não notar o set -S anterior. Isso é basicamente o que eu quero também. Também notei que havia várias preocupações que outras pessoas tinham sobre essa nova opção. Posso dar meus pensamentos sobre essas preocupações abaixo (já que o conjunto de peixes não usou -s como opção, usarei -s para me referir a --separator seguir):

  1. --no-modify modifica alguma coisa. Sim, e você deve alterar o nome para ser explícito, por exemplo, --change-separator .
  2. Existem alguns casos de canto/complicados. Isso se deve basicamente à sintaxe não bem definida, e pode ser evitado naturalmente se dermos uma definição estrita da sintaxe. Por exemplo:

    1. Ideia básica: cada var (lista) é associada ao seu próprio separador quando definido (o padrão é ' ' ). Este separador será usado quando este var for criado a partir de string e quando for convertido em string (esta é uma ideia comum em algumas linguagens como a função join() do Python). Um var é convertido em string quando exportado ou quando o usuário deseja fazer isso.

    2. Como criar vars de ambiente



      1. set ENV_VAR a b c . Sem -s , escolhemos ' ' como separador padrão.


      2. set -s ':' ENV_VAR . Nesse caso, ENV_VAR é definido como uma lista vazia.


      3. set -s ':' ENV_VAR a b:c d e:f . Nesse caso, os usuários que escrevem este código devem entender claramente que ':' é o separador e entender que ENV_VAR será um array como ['a b', 'c d e', 'f'] e será exportado como 'a b:c d e:f' . E se você quiser que o ENV_VAR exportado comece com espaços e termine com espaços? Você deve usar escapes como: set -s ':' ENV_VAR \ a b:c d e:f\ . Então ENV_VAR será [' a b', 'c d e', 'f '] e será exportado como ' a b:c d e:f ' .


      4. set -s ':' ENV_VAR a b:c d e:f $ENV_VAR . Neste caso, depende de como $ funciona. Se for definido como extrair o valor da string de ENV_VAR em vez da lista, este comando será o mesmo que substituir $ENV_VAR pelo valor da string convertido da lista abaixo e, neste caso, set -s ':' ENV_VAR a b:c d e:f:$ENV_VAR é provavelmente o que você realmente quer (observe o : depois f ); se for definido como extrair a variável de ENV_VAR (que é uma lista em vez de uma string), isso deve se tornar uma operação de extensão de lista, assim como em python. Por exemplo, neste último caso, se ENV_VAR for ['x', 'y'] antes, então após esta operação ENV_VAR se tornará ['a b', 'c d e', 'f', 'x', 'y'] . E se o separador anterior ENV_VAR não for ':' ? No primeiro caso, é sua responsabilidade certificar-se de que está fazendo a coisa certa, por exemplo, você provavelmente deve usar um separador consistente alterando o separador original para ':' ou alterando o separador atual para o original. No último caso, isso definirá o separador desse array do original (não importa o que seja) para ':' .



    3. Como alterar o separador



      1. set --change-separator ':' ENV_VAR . Se ENV_VAR não existir, o programa deve sair com um código de erro diferente de 0. Fácil e explícito o suficiente.



    4. Como visualizar o separador



      1. set --view-separator ENV_VAR .



Além disso, eu realmente acho que esse problema é óbvio e urgente e um grande ponto de dor para os usuários e espero que esse problema possa ser resolvido o mais rápido possível, porque isso realmente afeta muito a experiência do usuário. Na verdade, não encontrei outros problemas (mesmo muito pequenos) por enquanto usando o peixe, exceto este tão grande.

Eu realmente acho que esse problema é óbvio e urgente

@thuzhf : Eu diria que você está superestimando isso.

Uma razão é que seu problema em #5169 era com $LD_LIBRARY_PATH, mas isso não é realmente uma lista em peixes! Você deve configurá-lo como set LD_LIBRARY_PATH "$LD_LIBRARY_PATH:/some/path" , assim como em outros shells.

Fish transforma exatamente três variáveis ​​herdadas/exportadas em listas automaticamente:

$PATH, $MANPATH e $CDPATH. E exatamente essa lista terá um separador ":" quando exportada.

Outras variáveis ​​"padronizadas" como $LD_LIBRARY_PATH não devem ser tratadas como listas no fishscript, então você não tem esse problema. Variáveis ​​que não são padronizadas você pode manipular como quiser, já que outros programas não farão nada com elas de qualquer maneira, então o separador não é crítico.

@faho Obrigado pela sua explicação clara. Isso realmente faz muito sentido para mim. OK, posso dizer que este problema está resolvido para mim.

Dei uma olhada no problema MANPATH descrito em #2090. O cenário é anexar ao manpath para que ele continue usando os caminhos do sistema.

No bash, escreveria isso como export MANPATH="$MANPATH:/new/path" . Se MANPATH estiver definido, isso será anexado a ele. Se não estiver definido, isso irá preceder dois pontos, que é uma indicação específica do homem para usar os diretórios do sistema. Esta sintaxe não funciona em fish; o problema é que MANPATH é uma matriz e, portanto, "$MANPATH" terá espaços em vez de dois pontos.

Uma abordagem de "variáveis ​​vinculadas" nos permitiria ter, por exemplo fish_manpath como um array que espelha MANPATH como uma string separada por dois pontos. Isso poderia ser construído inteiramente em script de peixe. No entanto, gostaríamos de fazer isso para todas as variáveis ​​semelhantes a caminhos, não apenas MANPATH, e isso seria uma quebra de compatibilidade significativa que não está claro como gerenciar. Também tem os mesmos problemas, por exemplo, a variável de matriz manpath em zsh é difícil de anexar, então não está claro por que ela existe.

Minha proposta aqui não torna a situação do MANPATH melhor ou pior; Eu acho que a coisa a fazer é punt e apenas ter uma história fácil para anexar ao MANPATH, que é esta:

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

Isso não é muito doloroso para colar no config.fish.

Minha proposta aqui não torna a situação do MANPATH melhor ou pior; Eu acho que a coisa a fazer é punt e apenas ter uma história fácil para anexar ao MANPATH, que é esta:

@ridiculousfish : Na verdade, estive pensando em dar um passo adiante: divida essas variáveis ​​especiais em ":" também na atribuição e junte-as com ":" em vez de espaço na expansão entre aspas.

Isso significa que quando você faz set -gx MANPATH "$MANPATH:/new/path" , o peixe vai e executa a divisão automaticamente, resultando no equivalente a set -gx MANPATH "" /new/path .

Agora, isso significa que ":" não pode aparecer em um caminho em $MANPATH (e $PATH e $CDPATH), mas eles não podem fazer isso de qualquer maneira porque quebraria utilitários não-fish!

Isso também nos permitiria talvez um dia remover o tratamento especial, porque adiciona uma maneira de compatibilidade cruzada de lidar com isso - você só teria que atribuir com o : e usá-lo com (string split : -- $MANPATH) , e funcionaria mesmo se esse tratamento fosse removido.

@faho Estou gostando da ideia - como o usuário marcaria uma variável como recebendo esse tratamento especial? splitenv faria isso?

como o usuário marcaria uma variável como recebendo esse tratamento especial?

Minha ideia era realmente não permitir marcação - apenas deixe como comportamento especial para $PATH et al. O que nos deixaria longe de listar em algum momento no futuro.

No entanto, desde então entendi que permitir isso para outras variáveis ​​também nos ajuda com outras variáveis ​​- por exemplo, eu disse antes que meu $EDITOR é definido como um elemento ( set EDITOR "emacs -nw" ) para compatibilidade com ferramentas, mas os peixes gostariam mais se fosse uma lista.

Então, eu provavelmente usaria como padrão _space_ como um delimitador, a menos que seja semelhante a PATH (e supondo que seja se o nome terminar em PATH provavelmente está bem).

Splitenv faria isso?

Eu realmente não gosto de introduzir outro builtin para isso, então eu provavelmente iria com a opção argument-to-set.

Concordo que "PATH/MANPATH/CDPATH de caixa especial é estranho; precisamos de uma solução mais geral".

Proponho que PAREMOS o PATH/MANPATH/CDPATH de invólucro especial. Eles seriam tratados (pelo usuário final do peixe) da mesma forma que são em outras conchas. $PATH (e os outros) seria uma única string (ou no jargão dos peixes uma lista com um comprimento de 1) com dois pontos. Observe que estou me referindo à experiência do usuário fish, não a como essas coisas são tratadas internamente; Eu não sei como seria a implementação dentro do fish - eu confio nos outros para apontar quaisquer problemas lá.

Claro, teria a desvantagem de uma incompatibilidade com versões anteriores, mas acho que valeria a pena como um grande ganho em simplicidade e elegância. Acho que atenderia ao número 2090 também.

O que todos pensam?

5245 foi mesclado, então isso parece resolvido.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

pawlosck picture pawlosck  ·  3Comentários

Limeth picture Limeth  ·  3Comentários

mqudsi picture mqudsi  ·  3Comentários

krader1961 picture krader1961  ·  3Comentários

andrewhowdencom picture andrewhowdencom  ·  3Comentários