Fish-shell: PATH/MANPATH/CDPATH de mayúsculas y minúsculas es raro; necesitamos una solución más general como zsh variables "atadas"

Creado en 11 dic. 2012  ·  52Comentarios  ·  Fuente: fish-shell/fish-shell

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

Esto resulta en:

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

Está claro que el carácter \x1e se trata especialmente como delimitador de elementos.

enhancement

Todos 52 comentarios

¿La preocupación es que no hay forma de representar \x1e? ¿O estás pensando en mejoras arquitectónicas?

Creo que el separador de matrices se usa principalmente en matrices persistentes en lugares que solo aceptan cadenas, como variables universales o variables de entorno.

在 2012-12-12 上午2:09, notificaciones "ridiculousfish"@github.com写道

¿La preocupación es que no hay forma de representar \x1e? o estas pensando
sobre mejoras arquitectónicas?

Yo diría que tengo ambas preocupaciones en mente. Para el primero, solo piense en un
nombre de archivo con \x1e incrustado. POSIX dice cualquier cosa menos \0 está permitido en
nombres de archivo, por lo que es perfectamente posible. Usar \0 como delimitadores de matriz puede ser
una opción un poco mejor, pero eso lleva a la segunda preocupación: es
frágil y claramente equivocado.

Creo que el separador de matrices se usa principalmente en matrices persistentes en lugares
que solo toman cadenas, como variables universales o variables de entorno.

Si persistente significa "serializado", no. Los arreglos siempre se almacenan en
Forma delimitada por \x1e. Las matrices de entorno exportadas se unen mediante ":". Ellos
sin embargo, se utilizan en variables universales, que en mi humilde opinión deberían implementarse
con un escape adecuado en su lugar.


Responda a este correo electrónico directamente o véalo en GitHub.

¿Qué tal usar un carácter de área de uso privado como separador? Fish ya usa algunos de esos en algunos casos.

@JanKanis Eso no es mejor; es perfectamente posible en nombres de archivos (considerando los sistemas de archivos que usan codificaciones nativas no utf8) y otras cadenas.

Diría que, entre otros, "\0" es una opción _ligeramente_ mejor entre otros, ya que es el único carácter que UNIX prohíbe en los nombres de archivo, pero aún me huele mal. Además, ya estamos dividiendo y ensamblando muchas matrices, espero que la implementación de matrices verdaderas resulte en una mejor arquitectura y menos código.

Fish ya maneja caracteres de uso privado y bytes no válidos cuando codifica cadenas externas para wchars. Estos valores especiales se codifican byte a byte en un conjunto específico de caracteres de uso privado que Fish también decodifica nuevamente en la salida, por lo que, en principio, podría funcionar usar otro carácter de uso privado. Sin embargo, estoy de acuerdo en que usar matrices verdaderas es mucho mejor. Hay una complicación en que la comunicación entre fish y fishd ocurre a través de un socket que usa cadenas utf8, y allí fish usa (creo) la secuencia de escape "\x1e" (en lugar de un byte 0x1e) para separar los elementos de la matriz. Pero eso probablemente podría resolverse usando, por ejemplo, una secuencia de escape privada no utilizada.

Comparto las preocupaciones de xiaq, pero (para las prácticas) encuentro que la división implícita en \n es mucho más ofensiva:

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

¡La interpretación de la matriz (delimitada por saltos de línea) de la salida del subproceso debe ser explícita y opcional!

Pero eso probablemente no tenga nada que ver con el almacenamiento subyacente de las matrices...

@xiaq : ¿Qué tiene de malo usar \0 ? xargs parece usarlo como su opción "confiable".

No puede usar \0 en variables de entorno, por lo que sería difícil exportar matrices a shells secundarios.

Estoy migrando desde zsh donde uso esta secuencia para definir $LESS env var de una manera sensata aprovechando su función de variables "atadas":

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

He omitido la lista completa de opciones por razones de brevedad. En zsh, eso da como resultado que $LESS env var sea una lista separada por espacios de las opciones en la matriz $less. El equivalente en fish da como resultado que los elementos estén separados por el carácter separador de registros (\x1e). A pesar de que la documentación dice que los elementos de la matriz estarán separados por espacios (módulo de las matrices especiales como PATH). Tengo que hacer explícitamente una asignación que interpole los valores en una sola cadena para obtener el resultado esperado:

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

Por el momento, realmente no me importa si \x1e se usa internamente para serializar matrices en lugar de \x00. Me importa que las matrices exportadas tengan sus elementos separados por \x1e. Eso está roto, mal, fubar. Elige tu adjetivo. También es inconsistente con la solución alternativa mencionada anteriormente y el comportamiento documentado. Este problema debe etiquetarse como un error en mi humilde opinión.

PD: en ninguna parte de la documentación se menciona el uso del carácter separador de registros (\x1e). Que es otro problema.

@ krader1961 Gracias por compartir esto. No existe una convención estándar de Unix para las variables de entorno tipo lista: algunas están delimitadas por dos puntos, otras están delimitadas por espacios. fish usa \x1e para que pueda distinguir sus propios arreglos.

¿Puede señalarnos la documentación errónea?

¿Cómo cree que se exportarán las matrices: dos puntos, espacios, líneas nuevas, algo más? ¿Los peces también deberían tokenizar las variables de entorno en este personaje?

Parece que menos espera argumentos delimitados por espacios. Probablemente la solución más simple sea set -x LESS '--HILITE-UNREAD --LONG-PROMPT' , etc.

No existe un estándar para las variables de entorno de tipo lista porque, por definición, son una secuencia arbitraria de bytes compuesta por una clave y un valor separados por un signo igual y terminados por un byte nulo. Ni siquiera tienen que ser caracteres imprimibles. La única convención ampliamente aceptada para un mayor nivel de abstracción es la establecida por la función execlp() para PATH env var.

La documentación es errónea en la medida en que no menciona el uso de \x1E, \036, 30 o el carácter "separador de registro" para separar elementos de una matriz al exportar una var con más de un elemento. La documentación dice que

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

Eso es de la sección "Expansión de variables" en http://fishshell.com/docs/current/index.html. Es razonable inferir que esa declaración también se aplica a las variables exportadas que no están en mayúsculas y minúsculas como se documenta en las secciones "Matrices" y "Variables especiales" de ese mismo documento.

Tengo la sensación de que fish no debería tokenizar automáticamente las variables env en una lista fuera de las variables de casos especiales delimitadas por dos puntos, como PATH. Sin embargo, debe haber un medio sólido por el cual un usuario pueda tokenizar una var en una matriz en un carácter arbitrario.

En ausencia de un mecanismo para configurar el carácter que se utilizará en una base de var por var (como el comando zsh "typeset -T"), se debe usar un espacio al concatenar los elementos de la matriz (nuevamente, excluyendo los vars de casos especiales separados por dos puntos ). Obviamente, esto no se aplica a los almacenes de datos privados, como el almacenamiento de variables universales.

Por último, no pude encontrar ningún uso en las funciones de pescado estándar donde se usa un env var para pasar una matriz que contiene más de un elemento a otra función o secuencia de comandos. Tales casos de uso pueden existir, pero deberían requerir que los scripts cooperen explícitamente en la serialización/deserialización de los datos en lugar de depender de fish para reconstruir implícitamente matrices a partir de vars cuyas cadenas contienen el carácter separador de registros.

Gracias por tu atenta respuesta. La sección que citó sobre la concatenación usando espacio es específicamente para cadenas entre comillas dobles. Deberíamos agregar alguna discusión sobre lo que sucede con las matrices exportadas.

Los usuarios pueden tokenizar cadenas con, por ejemplo set SOMEPATH (string split : $SOMEPATH) .

La desventaja de las variables exportadas de concatenación espacial es que se modifican cuando fish se ejecuta de forma recursiva. Hoy esto funciona:

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

Pero si exportáramos con espacios, esto mostraría 1 para la llamada recursiva. Como dices, no confiamos en esto, pero es bueno desde el punto de vista de la consistencia.

Gracias por tu atenta respuesta.

¡Tendré que secundar eso! Siempre es bueno tener una nueva perspectiva de las cosas.

Para aquellos nuevos en esta discusión, creo que tendré que mencionar algunas de las cosas relacionadas con esto.

Lo que me viene a la mente de inmediato es la lista blanca de listify , que aparece en problemas como #2090.

Esto significa que para $PATH, $CDPATH y $MANPATH, aparecerán como listas/matrices para pescar, pero cuando se exporten, se unirán con ":" nuevamente. Luego, un pez dentro de un pez los dividirá nuevamente. Esto opera con dos puntos, no con \x1e. Según mi comprensión del código , parece hacerlo en cada dos puntos, sin posibilidad de escapar, por lo que podría romperse en las entradas de $ PATH con dos puntos dentro de ellas, lo que UNIX permite dentro de las rutas de archivo, aunque parece roto para $ PATH al menos . Este esquema también se utiliza para, por ejemplo, PYTHONPATH y GOPATH.

Me encantaría tener algo un poco más explícito para dividir las variables de entorno que el implícito siempre-dividir-en-\x1e-excepto-por-estos-tres-dividirlos-en-dos puntos, porque en realidad se trata de dos esquemas diferentes en one y exportar una lista actualmente siempre confundirá todo menos el pescado.

Mi solución preferida sería una función 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

(Si string split tuviera superpoderes , esto sería un poco más simple)

Luego, todas las listas se unirían con dos puntos cuando se exportaran, por lo que un usuario puede separarlas explícitamente con splitenv (aunque no estoy totalmente inmerso en una función de ayuda, creo que hacer esto trivial es una buena cosas que hacer). Para compatibilidad con versiones anteriores, splitenv PATH CDPATH MANPATH se ejecutaría al inicio. Si un usuario desea exportarlo de manera diferente, string join está disponible.

Todo esto significa que ya no necesitamos \x1e, tenemos un esquema que al menos tiene la posibilidad de ser entendido por otros programas, pero el pez dentro del pez (bastante exótico en mi humilde opinión) ahora se convierte en fish -c 'splitenv list; count $list' .

El problema es, por supuesto, que, como se mencionó, el esquema habitual de lista separada por dos puntos no tiene forma de escapar de los dos puntos, y si quisiéramos agregar uno, string split no tiene un "--sin escape" Opción de dividir solo en separadores sin escape.

¿Estoy teniendo algún sentido?

@faho Creo que esa idea tiene mérito. La peor parte del antiguo esquema era dividir implícitamente en dos puntos, lo que destrozaría las variables que no deberían dividirse. En su idea, esto es (casi) siempre explícito, por lo que creo que es bastante seguro.

Con respecto a escapar, no escapar dos puntos en PATH es intencional según el enlace que encontró. Dudo que PYTHONPATH, CLASSPATH, etc. sean más consistentes en este sentido. Dado que no puede usar dos puntos en estos caminos, podemos elegir si lo escapamos o no; pero si escapamos de dos puntos, necesitamos escapar de las barras invertidas, y apuesto a que puedes tener una barra invertida en PATH. Es posible que necesitemos una lista blanca de "no escapar" (ugh).

Alternativamente, no nos preocupamos por eso, y simplemente dejamos que los dos puntos actúen como delimitadores. Creo que me inclino por esto por su simplicidad y familiaridad con otras conchas.

Todavía nos enfrentamos al problema de que algunas variables similares a listas están delimitadas por espacios y otras están delimitadas por dos puntos. Una posibilidad es que splitenv acepte un delimitador, lo recuerde y lo use para reconstruir el valor en la exportación:

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

Estas llamadas ahora juegan el doble papel de importar cualquier variable existente y marcar cómo se exporta. ¿Qué piensas?

Además, ¿hay alguna manera de hacer esto sin editar config.fish? ¿Quizás como parte de variables universales?

Todavía nos enfrentamos al problema de que algunas variables similares a listas están delimitadas por espacios y otras están delimitadas por dos puntos. Una posibilidad es que splitenv acepte un delimitador, lo recuerde y lo use para reconstruir el valor en la exportación:

Suena bien. Aunque en ese momento hacer de splitenv un script probablemente no ayudaría, ya que de todos modos necesitaríamos la cooperación del lado de C++.

Estas llamadas ahora juegan el doble papel de importar cualquier variable existente y marcar cómo se exporta.

Es posible que ahora "splitenv" ya no sea el nombre perfecto (lo fue cuando lo pensé, por supuesto :risas: ) - También he considerado "listificar".

Aunque me molesta que no pueda recordar dónde hemos tenido una discusión relacionada antes, creo que tendré que revisar los problemas nuevamente esta noche.

Los usuarios pueden tokenizar cadenas con, por ejemplo set SOMEPATH (string split : $SOMEPATH) .

El comando string no está documentado en ninguna parte que pueda encontrar. Además, man string muestra la página del manual string(3) que documenta las funciones de manipulación de cadenas en BSD (y Mac OS X).

Pero si exportáramos con espacios, esto mostraría 1 para la llamada recursiva. Como dices, no confiamos en esto, pero es bueno desde el punto de vista de la consistencia.

Ese comportamiento es, sin embargo, sorprendente. Estoy dispuesto a apostar que si le preguntas a 100 personas qué sucede cuando se exporta una var con más de un elemento, 90 de ellas dirán que los valores están concatenados con espacio como separador. Algunos podrían decir que la coma u otro carácter se usa como separador. Y las dos personas que ejecutaron env dirán que los valores están concatenados sin separador porque, a menos que filtre la salida a través de algo como cat -evt el carácter separador de registro es invisible.

que aparece en ediciones como #2090

Lo siento, pero no veo ningún mérito en la queja de ese usuario. El problema se soluciona de manera trivial probando explícitamente si MANPATH ya está configurado. Lo cual, me parece, es algo que tienes que hacer en cualquier caso, dada la semántica de los dos puntos iniciales frente a los finales.

por lo que podría romperse en las entradas $PATH con dos puntos dentro de ellas

Es al menos treinta años demasiado tarde para arreglar eso. No deberíamos implementar el escape de dos puntos (y por extensión el carácter de escape) ya que sería un comportamiento no estándar. Hasta hace poco, pasé más de 20 años como especialista en soporte de UNIX. Nunca escuché a alguien quejarse de que la presencia de dos puntos en un directorio incrustado en $PATH o una variable similar fuera un problema.

Mi solución preferida sería una función como splitenv var1 var2 var3

Está bien, aunque no está claro por qué los string split (no documentados) no son suficientes. Independientemente de si necesitamos una nueva función, definitivamente no deberíamos agregar nuevas variables de entorno de división automática. Los únicos dos que son lo suficientemente comunes como para garantizar ese comportamiento son PATH y CDPATH (y MANPATH ya que ya está en un caso especial). Un usuario puede dividir explícitamente otras variables como PYTHONPATH si lo encuentra útil.

Sin embargo, habiendo dicho eso, ciertamente debería haber una manera de registrar que una var determinada (por ejemplo, PYTHONPATH) debería tener sus elementos concatenados con un carácter separador específico cuando se exporta. La forma más natural de hacerlo es a través de una nueva opción para el comando set . Por ejemplo,

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

Esto no afectaría la forma en que se almacena el var en el almacén de datos de var universal donde aún se usaría el carácter de separador de registros y se dividiría automáticamente cuando se carga desde ese almacén de datos. Se determinará si el carácter separador registrado para la exportación también debe afectar la interpolación de cadenas. Mi sensación es que debería. Es decir, si se ejecuta el comando "establecer" anterior, entonces un subsiguiente

echo "PYTHONPATH is $PYTHONPATH"

debe usar dos puntos en lugar de un espacio para concatenar los valores de PYTHONPATH. El separador predeterminado es un espacio para conservar la semántica existente y minimizar la sorpresa para el usuario. Tenga en cuenta que las variables en mayúsculas y minúsculas como PATH también usarían dos puntos en ese ejemplo. Lo cual es incompatible con el comportamiento actual pero es consistente con la nueva semántica y menos sorprendente. En otras palabras, ¿por qué los elementos de $PATH están separados por dos puntos en el entorno exportado pero espacios en la salida de

echo "PATH is $PATH"

El comando de cadena no está documentado en ningún lugar que pueda encontrar. Además, man string muestra la página man string(3) que documenta las funciones de manipulación de cadenas en BSD (y Mac OS X).

Tranquilo tigre. Está en las versiones de desarrollo: consulte https://github.com/fish-shell/fish-shell/blob/master/doc_src/string.txt

Eso está bien, aunque no está claro por qué la división de cadenas (no documentada) no es suficiente.

Mi idea original era que es una función de conveniencia, por lo que esta operación se vuelve completamente trivial. Con la propuesta de @ridiculousfish , se convierte en algo más y ajusta una especie de tienda para que la variable también se una a ese carácter cuando se exporte. string split es solo un comando que divide una cadena, básicamente nuestra versión de cut .

La forma más natural de hacerlo es a través de una nueva opción para el comando set.

Esa es otra opción, aunque no estoy completamente convencido de la semántica. Por ejemplo set -S ':' PYTHONPATH . ¿Eso establecería PYTHONPATH en la lista vacía o simplemente dividiría el PYTHONPATH existente? Hasta ahora, todas las opciones establecidas han hecho lo primero, por lo que tendría que hacer set -S ':' PYTHONPATH $PYTHONPATH . O haríamos que _no_ hiciera eso y tendríamos inconsistencia dentro de la misma herramienta.

En otras palabras, ¿por qué los elementos de $PATH están separados por dos puntos en el entorno exportado pero espacios en la salida de echo "PATH is $PATH"

Esa es realmente una buena pregunta. Por supuesto, no esperaría que el separador apareciera, por ejemplo, en for p in $PATH; echo $p; end , pero unirlo con el carácter del separador por variable podría ser lo correcto. Por supuesto, hay string join para hacerlo manualmente.

Ese comportamiento es, sin embargo, sorprendente. Estoy dispuesto a apostar que si le preguntas a 100 personas qué sucede cuando se exporta una var con más de un elemento, 90 de ellas dirán que los valores están concatenados con espacio como separador.

Hay un problema general con hacer diseño por encuesta y pescar. Porque las personas encuestadas con frecuencia tendrían conocimiento de bash (y en menor medida de otros proyectiles POSIXy) mientras que la idea misma de fish es hacer algo _mejor_ al abandonar al menos algo de POSIX.

Eso no quiere decir que sea completamente inútil, es solo algo a tener en cuenta: si nos atenemos a este tipo de ideas, tendríamos el comportamiento de división de palabras de bash y if-fi.

¿ set -S ':' PYTHONPATH establecería PYTHONPATH en la lista vacía o simplemente dividiría el PYTHONPATH existente?

Lo establecería en una lista vacía. Si el usuario desea conservar el valor existente, debe incluirlo explícitamente (ver más abajo).

Ya tenemos todas las capacidades necesarias con la excepción de un medio para configurar el carácter (o la cadena vacía) que se usará al concatenar elementos de matriz de una var dada para exportación o interpolación. Si alguien quiere manipular una variable como PYTHONPATH, puede tratarla como una cadena simple:

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

O pueden tratarlo como una matriz:

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

Tenga en cuenta que mi propuesta de usar el carácter de división/concatenación en lugar de un espacio al interpolar en una cadena proporciona un comportamiento consistente independientemente de si el usuario divide o no la var en una matriz.

Definitivamente no estoy sugiriendo un diseño por comité. De esa manera se encuentra la locura y bogosities como zsh. Simplemente estoy señalando que cuando se dan dos o más opciones sin otra razón para elegir una sobre otra, elegir la opción que menos sorprenda al usuario del shell es la mejor opción. También es por eso que (por el momento) me opongo a la introducción de nuevos comandos o comportamientos, como la división automática de variables (aparte de PATH y CDPATH, por supuesto). Este es el tipo de cosas que se hacen con poca frecuencia y, por lo general, solo en config.fish y algunas funciones especializadas como el script "activar" de Anaconda. Y la forma de hacer que este último se comporte correctamente independientemente de si el usuario ya ha dividido o no la var en una matriz en su config.fish es tratarla siempre como una cadena que debe dividirse. Por ejemplo, si fuera necesario modificar PYTHONPATH, podría hacer algo como esto:

# 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

O, más simplemente,

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

Sí, eso potencialmente convierte lo que pudo haber sido una cadena simple en una matriz. Pero con mi regla de que el carácter especificado por el interruptor -S se usa al exportar e interpolar esa conversión en una matriz, no debería importar en la práctica. Hay, sin embargo, un caso de esquina. ¿Qué sucede si el usuario no ha convertido explícitamente la var en una matriz en su config.fish y luego ejecuta algo como el script hipotético anterior? La var se convierte potencialmente en una matriz de elementos múltiples, lo que significa que si posteriormente lo hacen

for elem in $PYTHONPATH
   echo $elem
end

Eso no ejecutará el cuerpo del bucle for solo una vez con el valor en forma de directorios separados por dos puntos, como podría esperar el usuario, ya que desconocía la división realizada por el guión hipotético de "activar". Creo que podemos vivir con eso, ya que sería perverso que un usuario hiciera algo así.

tl; dr Creo que las listas deberían "recordar" su delimitador y debajo está el por qué.


Estoy de acuerdo con mucho de la mayoría de los anteriores. Sin embargo, una cosa que todavía parece tediosa es que los comandos anteriores todavía parecen demasiado detallados; es decir, a veces es más sencillo describir algunos de estos comandos en un lenguaje sencillo.

Como ejemplo (y no me estoy enfocando tanto en la longitud como en la cantidad de cosas repetidas):

  • pescado: set -S ':' PYTHONPATH /activated/python/tree (string split ':' $PYTHONPATH)
  • Inglés: "añadir /activated/python/tree a PYTHONPATH ( : -delimited`)"

Hay dos cosas repetidas aquí: PYTHONPATH y el delimitador : . Podría decirse que PYTHONPATH debería repetirse por dos razones, y ninguna de estas dos razones se aplica al delimitador.

  1. No es difícil intuir lo que sucede cuando alguien dice set PYTHONPATH /activated/python/tree $PYTHONPATH , porque esto es muy similar a cosas como i = 2 + i , que es un concepto/modismo muy familiar. (Pero todavía tenemos atajos como += , por lo que propongo la bandera --append a continuación). Por otro lado, cuando las personas piensan en agregar a una lista, no piensan en dividir y unirse en un delimitador. No piensan en convertir la lista completa a algún otro formato, hacer la operación real y volver a colocarla. En su mente, naturalmente leen el delimitador como un delimitador en lugar de cambiarlo a algún delimitador "interno" o "preferido".
  2. El uso de un comando simple set para agregar guarda la adición de otro comando para unir dos listas diferentes. Por otro lado, convertir de un delimitador a otro es algo que, idealmente, nunca queremos que el usuario haga manualmente, principalmente por el motivo anterior.

Por el contrario, sugiero otra forma de especificar el delimitador en las listas: asociarlo con la lista indefinidamente. Entonces, el ejemplo anterior podría hacerse de la siguiente manera:

# 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

Implicaciones/preguntas de seguimiento/etc:

  1. Esto es bastante compatible con la sugerencia actual. Estos son los cambios necesarios:

    • Haga que el delimitador se mantenga (posiblemente usando otra variable como __fish_sep_PYTHONPATH )

    • (opcional) Agregue una bandera que actualmente estoy llamando --no-modify , que le dice a fish que cambie el delimitador de una lista sin cambiar su contenido. Posiblemente también agregue los indicadores --append y --prepend debido a la razón (1) anterior. De todos modos, este no es necesario, como muestra la solución anterior, al estilo de cómo se agregan y anteponen hoy en día los peces.

  2. En fish, las listas deben por lo menos _ser tratadas_ como ciudadanos de primera clase. Esto significa que cambiar el delimitador debería cambiar la representación de la cadena, no la representación de la lista (a menos que el delimitador esté presente en uno de los elementos, en cuyo caso la división allí es inevitable). Por ejemplo, si cambia los delimitadores de , a : , ["0:1", "2"] debería convertirse en ["0", "1", "2"] y no ["0", "1,2"] (que es lo que sucedería si simplemente cambia el delimitador sin cambiar la cadena que respalda la lista). Este comportamiento debería maximizar la compatibilidad con el comportamiento actual y el hecho de que actualmente existe un delimitador inmutable predeterminado.

Aquí está el resultado final:

  • Esto implica muchas menos fichas y casi nada se repite.
  • Esto es paralelo al modelo mental que tienen muchos usuarios. Los usuarios piensan en estos términos: "anteponer", "establecer el delimitador", "no modificar".
  • Esta parece ser la única forma correcta de realizar esta tarea (la forma anterior ahora parece más torpe), por lo que estas adiciones no destruyen la ortogonalidad.
set --no-modify -S : PYTHONPATH
set --prepend PYTHONPATH /activated/python/tree

Gracias, @szhu , por el comentario detallado sobre mi propuesta. Sin embargo, hay muchos problemas con la solución propuesta. Por ejemplo, la adición de la opción --no-modify de hecho modifica la variable al convertirla en una lista y, por lo tanto, modifica la variable. Si bien rechazo casi todos los elementos de su propuesta, me hizo pensar en una solución más directa que abordaría la mayoría, si no todos, sus puntos. Tal vez debería haber un mecanismo para decirle a los peces que una variable env dada siempre debe dividirse y reconstituirse automáticamente en un token dado (por ejemplo, ":" o " "). Esto podría llamarse una designación de matriz automática y, cuando se ejecuta, cualquier valor existente se dividiría inmediatamente si aún no era una matriz.

Se podría agregar una nueva opción al comando set para activar este comportamiento. Sin embargo, me preocupa que hacerlo sea ambiguo y podría interpretarse como la definición de una variable sin valor. ¿Sería inequívoco agregar una opción de token -A al comando set ? Por ejemplo:

set -x -A ':' PYTHONPATH

Presumiblemente, eso convertiría inmediatamente cualquier PYTHONPATH env var existente en una matriz después de dividirse en dos puntos. Por el contrario, daría como resultado que los valores se concatenen en dos puntos cuando se exporten o interpolen en una cadena. De manera similar, incluso si PYTHONPATH no existiera en el momento en que se ejecutó el comando, la especificación de matriz automática se recordaría y los usos posteriores se verían afectados. Por ejemplo, esto obviamente crearía una matriz:

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

Pero, ¿qué pasa con ese último argumento? ¿Debería dividirse automáticamente en dos tokens?

Tenga en cuenta que este comportamiento solo debería aplicarse a las variables exportadas y, de lo contrario, se generaría un error. También hay algunos casos de esquina que necesitan ser explicados. Por ejemplo, ¿qué pasa si la declaración de división automática original incluye valores como en este ejemplo?

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

¿Deberían dividirse esos valores en el token de división automática? ¿O debería dar como resultado un error y requerir que se modifique el valor en una declaración separada? Y sea cual sea la sintaxis elegida, todavía tiene el problema de qué hacer con los valores que contienen el token de división automática. El diablo está en los detalles. Lo que quiere decir que puede haber otras ramificaciones de esta propuesta en las que no he pensado. Mi propuesta original con una sintaxis más detallada evita esos problemas por lo que sé.

@ krader1961 , gracias por tu respuesta. Sin embargo, parece pensar que estoy convirtiendo variables de cadenas a listas. Creo que estás malinterpretando un concepto importante en fish: cada variable es una lista de cadenas . Las variables que parecen cadenas son en realidad listas de longitud 1. fish no las trata de manera diferente a las listas de longitud 0 o 2 o cualquier otra longitud.

Además, tenga en cuenta que, si bien la cadena subyacente que se usa para pasar las variables de entorno puede cambiar cuando cambia los delimitadores, uno de los puntos fuertes de fish es que el usuario normalmente no necesita pensar en los delimitadores en absoluto. Esta es la razón por la que recomiendo que la opción -S especifique cómo se debe convertir esta lista en una cadena cuando se _exporta fuera_ de pescado. -S no debe cambiar la representación de la lista de peces (excepto en los casos en los que es imposible representar esa lista usando el delimitador de destino).

Por cierto, aquí hay un ejemplo que muestra cuán limpia es mi propuesta. Aquí hay un código para convertir una variable $L al delimitador predeterminado de \x1e . No tendrá absolutamente ningún efecto en ninguna variable (cualquier alcance, cualquier número de elementos) que se pueda crear en fish hoy.

set -S \x1e L $L

Una cosa más: la familia de argumentos --no-modify son solo atajos. Aquí están sus equivalentes:

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

(He dicho lo siguiente antes, pero creo que ahora puedo hacer un mejor trabajo explicándolo). Al enfatizar cuán "tontos" son estos tres argumentos, algunos pueden cuestionar si son necesarios. Se puede citar que el pez tiene un principio de diseño de ortogonalidad . Cuando todas las cosas son ortogonales, esto significa que para cualquier tarea importante que desee realizar, debe ser obvio qué conjunto de características elegir para realizar esa tarea; debe haber solo una forma correcta de hacerlo. Aquí, de hecho, agrego otra forma de anteponer/agregar/evitar la modificación de una lista, pero esto es solo porque creo que los equivalentes que se reemplazan son innecesariamente detallados; no deberían ser las formas correctas de agregar listas de modificación. Una forma de convencerte de esto es pensar en cómo piensas agregar a una lista. Probablemente piense "añadir $TOADD a $L " en lugar de "establecer $L a $L $TOADD ".

Déjame saber lo que piensas, y si esto es un caso más convincente para mi propuesta. (Además, es bastante común que no entienda bien las cosas, así que siéntete libre de corregirme).

@szhu Soy muy consciente de que todos los vars en fish son listas de cero, uno o más valores. Aparentemente, tampoco leyó mis comentarios anteriores en los que afirmo claramente que el delimitador asociado no debería afectar la representación interna o cómo se conservan los valores en el almacén de datos universal (aparte de almacenar el delimitador). Tampoco abordaste mis puntos anteriores. Considere su último ejemplo:

set -S \x1e L $L

¿Qué debería hacer si L ya contiene dos o más valores? Presumiblemente nada más que cambiar el delimitador asociado. ¿El argumento $L sería opcional en ese caso? ¿O debería primero convertir la matriz existente en una cadena simple (presumiblemente concatenando usando el delimitador existente) y luego dividir esa cadena en el nuevo delimitador? Como dije antes, el diablo está en los detalles.

En última instancia, los diseñadores y mantenedores establecidos decidirán si se debe agregar o no su familia de funciones --no-modify , pero voto no porque, en mi opinión, no agregan suficiente valor en relación con su costo.

Lo siento, este hilo es largo, debo haber perdido su reconocimiento de esto anterior; bueno saber que estamos en la misma página! Creo que también he abordado la mayoría de sus preocupaciones anteriormente, pero no todas. Me ocuparé específicamente de cada una de sus inquietudes a continuación.


1. ¿El $L es opcional en set -S \x1e L $L ?

El comportamiento existente de set no cambiará. Bajo el comportamiento actual, set L $L no cambia L y set L hace que L sea una lista vacía. Lo mismo con set -S \x1e L $L y set -S \x1e L .

1.1 ¿No parece set -S \x1e L $L demasiado detallado solo para cambiar el delimitador?

Levemente. Es por eso que propongo la opción --no-modify como atajo para esto.

Pero mi plan no se derrumbará si no existe este atajo. Ya nos ocupamos de este problema todos los días cuando agregamos listas: set PATH ~/.bin $PATH . Por eso, por la misma razón, propongo --prepend y --append también.

2. ¿Cómo se llevaría a cabo el proceso de conversión?

Digamos que nuestro antiguo delimitador es \x1e y el nuevo es : , y que tenemos una lista de peces ["hello", "world"] (exportada como hello\x1eworld ). Hay dos formas básicas de hacer la conversión (" opciones de conversión "):

  1. Usa ["hello", "world"] y conviértelo a ["hello", "world"] (exportado como hello,world )
    Ventaja: la representación de la lista no cambia.
  2. Usa hello\x1eworld y conviértelo a ["hello\x1eworld"] (exportado como hello\x1eworld )
    Ventaja: la representación del valor exportado no cambia.

Tenga en cuenta que esto es desde la perspectiva de la interfaz de usuario, no desde la perspectiva de la implementación; estamos hablando de cómo aparece para el usuario. Cubriré la implementación en la siguiente pregunta. _Nota: el resto de esta respuesta son cosas nuevas que no he abordado anteriormente, provocadas por sus preguntas. ¡Gracias!_

Dentro de pescado. Primero, si estamos trabajando completamente en peces, las listas son de primera clase y nunca debería tener que preocuparse por los delimitadores, por lo que ninguno de los dos es obligatorio. (Nuevamente, "debería" es desde la perspectiva del usuario, como desarrolladores, es nuestra responsabilidad hacer que esto sea cierto).

Cambiar el formato de exportación de vars. Por lo tanto, la única razón por la que un usuario necesitará cambiar los delimitadores es cambiar la cadena exportada para programas que leen variables de entorno. Para las listas que se crean en fish, definitivamente usaremos la opción de conversión 1 , porque el significado de la variable como lista es importante y está bien definido, por lo que debemos preservar la representación de la lista.

Cambiar el formato de importación de vars. Sin embargo, para variables de entorno como PATH que se crean inicialmente fuera de fish, necesitamos, para una lista que ya tiene un delimitador, decirle a fish cuál es ese delimitador. Para ello podemos utilizar la opción de conversión 2 .

2.1 ¿Cómo se implementaría esto?

Fish aunque el usuario no debería necesitar saber esto, fish en realidad almacena listas como cadenas. La variable x se almacena como hello\x1eworld . Según mi propuesta, habría otra variable, __fish_delimiter_x , que especifica el delimitador de la variable x . No existe en este momento, por lo que usamos el delimitador predeterminado, \x1e .

Para la opción de conversión 1:

  1. Divida la variable en el delimitador anterior, lo que da como resultado una lista verdadera en el lenguaje de implementación (C++).
  2. Únase a la lista usando el nuevo delimitador, lo que da como resultado una nueva cadena.
  3. Guarde el nuevo delimitador en __fish_delimiter_x .

Para la opción de conversión 1, una implementación equivalente:

  1. En la variable, reemplace todas las apariciones del delimitador anterior con el nuevo.
  2. Guarde el nuevo delimitador en __fish_delimiter_x .

Para la opción de conversión 2:

  1. Guarde el nuevo delimitador en __fish_delimiter_x .

2.2 Si necesitamos ambas opciones de conversión, ¿cómo especificaría el usuario cuál usar?

Quizás podamos tener dos opciones: -D o --convert-delimiter para la opción 1 y -d o --set-delimiter para la opción 2.

2.3 ¿Realmente necesitamos ambas opciones?

Debajo de los peces actuales, elegimos asumir que no veremos \x1e en la naturaleza fuera de los peces. Si mantenemos este como el delimitador predeterminado y mantenemos esta suposición, la opción de conversión 1 es suficiente para convertir y establecer el delimitador y no necesitaremos la opción de conversión 2 . (Una manera fácil de convencerse de esto es darse cuenta de que si la suposición es cierta, al convertir listas creadas externamente, el paso de la opción de conversión 1 "reemplazar todas las apariciones del delimitador anterior con el nuevo" no hará nada, reduciendo la conversión completa a la opción de conversión 2.)


@ridiculousfish , también agradecería sus comentarios sobre esto, específicamente con respecto a la interfaz de usuario y los detalles de implementación. ¡Gracias!

Parece que hay dos problemas aquí. ¿Hablemos del primero?

+1 para matriz verdadera

¿Es realmente necesario ese truco del separador para los peces? Ping #627

Revisando esto a la luz de mi solución para el problema n.º 2106 en el que noté que había dos formas incompatibles de convertir la representación de cadena para valores variables en matrices. Uno de los cuales elidió incorrectamente elementos vacíos. El problema central es que class env_var_t se basa en wcstring en lugar de en un vector de wcstring. Si cambiar eso vale la pena o no, está abierto a debate.

Si está siguiendo este número, lo animo a que eche un vistazo, y tal vez pruebe, PR #4082. Decidí que la mejor manera de abordar esto son las variables "vinculadas" similares a la característica del mismo nombre en zsh.

Parece que las preguntas que rodean estas listas exportadas por dos puntos y qué envvars deben incluirse en esta lista blanca, es algo que aún no se ha decidido. ¿Cuál es el estado actual en este asunto? ¿Podemos esperar una solución final a este tema? Justo hoy, volví a caer en la trampa de que LD_LIBRARY_PATH no está en la lista blanca...

Para resumir: las variables de entorno de Unix son cadenas, por lo que las variables de entorno tipo matriz deben usar un delimitador. La mayoría usa dos puntos ($PATH); aunque no todos lo hacen ($ MENOS). Nos gustaría usar dos puntos para delimitar todas las matrices en la importación/exportación (y, de hecho, fish solía funcionar de esta manera); el problema es que algunas variables planas contienen dos puntos ($DISPLAY, $SSH_CONNECTION).

El objetivo es hacer que las variables delimitadas funcionen de forma natural con el soporte de matrices de fish. @szhu sugirió mejorar set para rastrear un delimitador, pero la mejora de IMO set es el lugar equivocado para adjuntar esto:

  • Interacción molesta entre establecer la variable y establecer su delimitador (motivando --no-modify ).
  • Preguntas engañosas sobre cómo interactúan los delimitadores con el alcance variable.
  • Problemas en torno a variables universales. Tendríamos que enseñar a uvars a recordar el delimitador, y también alrededor de --no-modify ya que no hay forma de establecer una variable en su valor actual con uvars.

En la revisión, estoy a favor de la idea splitenv de @faho . splitenv name dividiría la variable existente en dos puntos, eso es todo. Es maravillosamente simple. Las variables que no usan dos puntos son lo suficientemente raras como para que no necesitemos soporte especial para ellas.

La desventaja es que las matrices exportadas de pescado se volverían a importar como una cadena delimitada por dos puntos; en la práctica creo que esto será raro.

No deberíamos infligir esta complicación de splitenv a los usuarios si podemos evitarla. Así que quiero ir un paso más allá y expandir la lista blanca de dos puntos a todas las variables de entorno cuyo nombre termina en PATH , por ejemplo, LD_LIBRARY_PATH, PYTHONPATH, etc. En la práctica, esto debería hacer lo correcto casi todo el tiempo; cualquiera que haya sido mordido por él puede usar string join para arreglar el valor.

Entonces lo que propongo (realmente la propuesta de faho):

  • Exporte todas las matrices usando dos puntos; no más separador de registros ASCII.
  • Implemente una función splitenv que divida una variable en dos puntos. Esto se puede escribir en escritura de pescado.
  • Mejore la lista blanca separada por dos puntos a todas las variables que terminan en PATH.

Creo que esto abordará la mayor parte del dolor asociado con las matrices delimitadas por dos puntos de una manera minimalista y compatible.

con respecto a la idea splitenv:

Digamos que quiero que fish exporte una lista cuyos elementos contengan dos puntos, por ejemplo: ["item1", "item:2"] . (No creo que esto sea una ocurrencia rara, especialmente cuando las matrices se usan para almacenar la entrada del usuario).

¿Se exportará la lista como item1:item:2 ? Si es así, será imposible recrear la lista original después de la exportación.

Además, tener una lista blanca inmutable para las variables se siente mal, aunque tener la lista blanca en *?PATH se siente menos mal. (Esa fue otra razón para mi propuesta de almacenar el delimitador como una variable: la lista blanca se puede cambiar configurando una variable).

@szhu Tienes razón. Exported-lists-can't-contain-colons es un problema que Unix ya sufre :

Ya que \

así que no me siento tan mal por introducir la misma limitación para el pescado (solo para variables exportadas).

Además, este problema solo ocurre cuando se exporta una matriz a una instancia de pez recursivamente invocada, lo que creo que será raro. Si esto resulta común, podríamos adjuntar datos secundarios en otra variable o usar un separador de matriz diferente al invocar fish de forma recursiva. Supongo que no necesitaremos ir tan lejos.

Estoy de acuerdo en que el caso extremo en el que la propuesta no funciona bien no es muy común, pero me temo que sería muy malo si la gente se topara con ella.

Aquí hay un ejemplo que solo es parcialmente artificial:

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

Puedo imaginarme a muchos usuarios nuevos confundidos después de observar lo anterior.

Creo que el siguiente comportamiento sería significativamente más agradable:

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

Me gustaría conocer su opinión y la de la comunidad al respecto.

¿Por qué no escapar de los dos puntos existentes? Eso preservaría la distinción.

Escapar tiene sentido para mí.

¿Podría ser confuso que no se recuerde si una variable es una matriz?

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

Si. Mi hipótesis es que exportar matrices no es común, fuera de las listas de rutas.

MANPATH tiene un significado especial para dos puntos dobles (::) - ver #2090 - ¿esto arroja una llave inglesa en las obras?

También diría que tener una variable de sidecar FISH_ARRAY_VARIABLES=FOO\t:\nBAR\t;\nBAZ\t-\n en cualquier caso sería una buena pista para instancias en las que se invoque a Fish para recoger las variables de matriz nuevamente, sin perturbar otros procesos y sin requerir un "estamos involucrando peces ahora "checker ..

re: https://github.com/fish-shell/fish-shell/issues/436#issuecomment -392409659 @zanchey
No he leído el #2090 en detalle, pero creo que la conversión entre la cadena delimitada por dos puntos y las formas de matriz es completamente transparente (excepto cuando los dos puntos ~no aparecen~ aparecen en los elementos de la matriz).

Para incluir dos puntos dobles en MANPATH , simplemente agregue una cadena vacía donde debería aparecer el doble punto:

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

Para comenzar MANPATH con dos puntos, simplemente agregue un elemento de cadena vacío al principio:

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

No he seguido todo aquí, pero como usuario quiero abogar por "sin configuración".
Creo que set -S y splitenv son formas de configuración. Algunos usuarios los harían en fish.config y manejarían PYTHONPATH como una matriz. Otros no lo harían y manejarían PYTHONPATH como una sola palabra delimitada por dos puntos. Copiar y pegar consejos de stackoverflow y ejecutar scripts que manipulen PYTHONPATH de un usuario a otro no siempre funcionaría...

Una regla fija "si termina con PATH " no requiere configuración y suena tan perfecta como se puede obtener :+1:
(No tengo opinión sobre si vale la pena la retroincompatibilidad)
Sí, set -x TEST2_PATH color:red font:serif se importaría como una matriz color red font serif , pero ese es el problema con la exportación de variables. Realmente no puede establecer una var exportada en una matriz sin comprender cómo funciona.

Si. Mi hipótesis es que exportar matrices no es común, fuera de las listas de rutas.

@ridiculousfish eso puede ser cierto en los caparazones actuales, pero me imagino que a medida que el pez gana más tracción, los usuarios podrían querer aprovechar la capacidad del pez para enviar listas a los caparazones de peces secundarios. Puedo imaginar que eventualmente puede haber programas/complementos que administren el estado de una sesión de pesca (revisaré este comentario en unos años para ver si esto es cierto), y ser capaz de universalmente auto-de/serializar listas hará que el código sea más limpio y menos complicado.


Una especie de pensamiento similar pero ligeramente diferente: tratar PATH como un caso especial es un caso límite anacrónico que los usuarios probablemente solo entiendan si tienen un historial de casos de uso típicos de shells. Esto limita la capacidad de fish para usarse como un lenguaje de secuencias de comandos general y limita algunos posibles casos de uso futuros.

@ridiculousfish Creo que una posible solución es asociar cada variable/matriz de entorno con su propio separador (y puede mantener '\x1e' o ' ' o ':' como predeterminado), y el usuario que crea la variable de entorno es responsable de elegir los separadores apropiados para evitar conflictos. El comando puede ser como: set --separator ':' TMP 1 2 3 . Por lo tanto, para esas variables de entorno conocidas, los usuarios pueden simplemente elegir los separadores conocidos correspondientes que también pueden ser reconocidos por otros programas y pueden hacer que Fish sea más compatible con más programas (como Python).

Para aquellos que solo están leyendo comentarios recientes, solo una nota de que la recomendación set --separator de @thuzhf es la misma que la recomendación set -S mencionada repetidamente a lo largo de este hilo. Para obtener más contexto sobre esa discusión, puede grep esta página para set -S .

@szhu Perdón por no darme cuenta de los set -S anteriores. Eso es básicamente lo que quiero también. También noté que había varias preocupaciones que otros tenían sobre esta nueva opción. Puedo dar mi opinión sobre estas inquietudes a continuación (dado que el conjunto de peces no ha usado -s como una opción, usaré -s para referirme a --separator ahora en adelante):

  1. --no-modify modifica algo. Sí, y debe cambiar el nombre para que sea explícito, por ejemplo, --change-separator .
  2. Hay algunos casos de esquina/complicados. Esto se debe básicamente a la sintaxis no bien definida, y se puede evitar naturalmente si damos una definición estricta de la sintaxis. Por ejemplo:

    1. Idea básica: cada var (lista) está asociada con su propio separador cuando se define (el valor predeterminado es ' ' ). Este separador se usará cuando esta var se cree a partir de una cadena y cuando se convierta a una cadena (esta es una idea común en algunos lenguajes como la función join() de Python). Una var se convierte en una cadena cuando se exporta o cuando el usuario quiere hacer esto.

    2. Cómo crear variables env



      1. set ENV_VAR a b c . Sin -s , elegimos ' ' como separador predeterminado.


      2. set -s ':' ENV_VAR . En este caso, ENV_VAR se configura como una lista vacía.


      3. set -s ':' ENV_VAR a b:c d e:f . En este caso, los usuarios que escriban este código deben entender claramente que ':' es el separador y entender que ENV_VAR será una matriz como ['a b', 'c d e', 'f'] y se exportará como 'a b:c d e:f' . ¿Qué sucede si desea que el ENV_VAR exportado comience con espacios y termine con espacios? Debe usar escapes como: set -s ':' ENV_VAR \ a b:c d e:f\ . Entonces ENV_VAR será [' a b', 'c d e', 'f '] y se exportará como ' a b:c d e:f ' .


      4. set -s ':' ENV_VAR a b:c d e:f $ENV_VAR . En este caso, depende de cómo funcione $ . Si se define como extraer el valor de cadena de ENV_VAR en lugar de la lista, entonces este comando será lo mismo que simplemente reemplazar $ENV_VAR con su valor de cadena convertido de la lista debajo, y en este caso, set -s ':' ENV_VAR a b:c d e:f:$ENV_VAR es probablemente lo que realmente quieres (observa el : después f ); si se define como la extracción de la variable de ENV_VAR (que es una lista en lugar de una cadena), entonces esto debería convertirse en una operación de extensión de lista como en python. Por ejemplo, en el último caso, si ENV_VAR es ['x', 'y'] antes, después de esta operación ENV_VAR se convertirá en ['a b', 'c d e', 'f', 'x', 'y'] . ¿Qué sucede si el separador anterior ENV_VAR no es ':' ? En el primer caso, es su responsabilidad asegurarse de que está haciendo lo correcto, por ejemplo, probablemente debería usar un separador consistente cambiando el separador original a ':' o cambiando el separador actual por el original. En el último caso, esto establecerá el separador de esta matriz de la original (sin importar cuál sea) en ':' .



    3. Cómo cambiar el separador



      1. set --change-separator ':' ENV_VAR . Si ENV_VAR no existe, el programa debe salir con un código de error distinto de 0. Fácil y lo suficientemente explícito.



    4. Cómo ver el separador



      1. set --view-separator ENV_VAR .



Además, realmente creo que este problema es obvio y urgente y un gran punto de dolor para los usuarios y espero que este problema se pueda resolver lo antes posible porque esto realmente afecta en gran medida la experiencia del usuario. En realidad, no he encontrado otros problemas (incluso muy pequeños) por ahora usando pescado, excepto este tan grande.

Realmente creo que este problema es obvio y urgente.

@thuzhf : Yo diría que estás sobreestimando eso.

Una razón es que su problema en #5169 fue con $LD_LIBRARY_PATH, ¡pero esa no es realmente una lista en fish! Debería configurarlo como set LD_LIBRARY_PATH "$LD_LIBRARY_PATH:/some/path" , al igual que en otros shells.

Fish convierte exactamente tres variables heredadas/exportadas en listas automáticamente:

$PATH, $MANPATH y $CDPATH. Y exactamente esta lista tendrá un separador ":" cuando se exporte.

Otras variables "estandarizadas" como $LD_LIBRARY_PATH no deben manejarse como listas en fishscript, por lo que no tiene este problema. Las variables que no están estandarizadas las puede manejar como quiera, ya que otros programas no harán nada con ellas de todos modos, por lo que el separador no es crítico.

@faho Gracias por tu clara explicación. Eso realmente tiene mucho sentido para mí. OK, puedo decir que este problema está resuelto para mí.

Eché un vistazo al problema MANPATH descrito en #2090. El escenario es agregar a manpath de modo que continúe usando las rutas del sistema.

En bash uno escribiría esto como export MANPATH="$MANPATH:/new/path" . Si se establece MANPATH, esto se agregará a él. Si no está configurado, esto antepondrá dos puntos, que es una indicación específica del hombre para usar los directorios del sistema. Esta sintaxis no funciona en fish; el problema es que MANPATH es una matriz, por lo que "$MANPATH" tendrá espacios en lugar de dos puntos.

Un enfoque de "variables vinculadas" nos permitiría tener, por ejemplo fish_manpath como una matriz que refleja MANPATH como una cadena separada por dos puntos. Esto podría construirse completamente en script de pescado. Sin embargo, nos gustaría hacer esto para todas las variables similares a rutas, no solo MANPATH, y eso sería una ruptura de compatibilidad significativa que no está claro cómo administrar. También tiene los mismos problemas, por ejemplo, la variable de matriz manpath en zsh es difícil de agregar, por lo que no está claro por qué existe.

Mi propuesta aquí no mejora o empeora la situación de MANPATH; Creo que lo que hay que hacer es despejar y simplemente tener una historia fácil para agregar a MANPATH, que es esta:

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

No es demasiado doloroso pegarlo en config.fish.

Mi propuesta aquí no mejora o empeora la situación de MANPATH; Creo que lo que hay que hacer es despejar y simplemente tener una historia fácil para agregar a MANPATH, que es esta:

@ridiculousfish : He estado pensando en ir un paso más allá, en realidad: divida estas variables especiales en ":" también en la asignación, y únalas con ":" en lugar de espacio en la expansión citada.

Eso significa que cuando haces set -gx MANPATH "$MANPATH:/new/path" , fish va y realiza la división automáticamente, lo que da como resultado el equivalente a set -gx MANPATH "" /new/path .

Ahora, esto significa que ":" no puede aparecer en una ruta en $MANPATH (y $PATH, y $CDPATH), pero no pueden hacer eso de todos modos porque rompería las utilidades que no son fish.

Eso también nos permitiría quizás algún día eliminar el manejo especial, porque agrega una forma compatible cruzada de manejarlo: solo tendría que asignar con : y usarlo con (string split : -- $MANPATH) , y funcionaría incluso si se eliminara ese manejo.

@faho Me entusiasma la idea: ¿cómo marcaría el usuario una variable para recibir este tratamiento especial? ¿Lo haría splitenv ?

¿Cómo marcaría el usuario una variable para recibir este tratamiento especial?

Mi idea era en realidad no permitir el marcado en absoluto, simplemente dejarlo como un comportamiento especial para $PATH et al. Lo que nos permitiría escapar de la lista en algún momento en el futuro.

Sin embargo, desde entonces he llegado a comprender que permitir esto para otras variables también nos ayuda con otras variables, por ejemplo, he dicho antes que mi $EDITOR está configurado como un elemento ( set EDITOR "emacs -nw" ) para compatibilidad con externos herramientas, pero a los peces les gustaría más si fuera una lista.

Por lo tanto, probablemente usaría _space_ por defecto como delimitador, a menos que sea similar a PATH (y suponiendo que lo sea si el nombre termina en PATH probablemente esté bien).

¿Splitenv lo haría?

Realmente no me encanta presentar otra función integrada para esto, por lo que probablemente optaría por la opción argumento a conjunto.

Estoy de acuerdo en que "el PATH/MANPATH/CDPATH de mayúsculas y minúsculas es extraño; necesitamos una solución más general".

Propongo que DETENGAMOS el PATH/MANPATH/CDPATH de carcasa especial. Serían tratados (por el usuario final del pescado) de la misma manera que en otras conchas. $PATH (y los demás) sería una sola cadena (o en la jerga de fish, una lista con una longitud de 1) con dos puntos. Tenga en cuenta que me refiero a la experiencia del usuario de peces, no a cómo se manejan estas cosas internamente; No sé cómo se vería la implementación dentro de fish; confío en que otros señalen cualquier problema allí.

De acuerdo, tendría la desventaja de una incompatibilidad con versiones anteriores, pero creo que valdría la pena como una gran ganancia en simplicidad y elegancia. Creo que también abordaría el #2090.

¿Qué piensan todos?

5245 se ha fusionado, por lo que parece resuelto.

¿Fue útil esta página
0 / 5 - 0 calificaciones