Fish-shell: No puedo leer la tubería para funcionar

Creado en 5 jul. 2012  ·  21Comentarios  ·  Fuente: fish-shell/fish-shell

Prueba:

function testfun
    set input (cat)
    echo $input
end

echo testing123 | testfun

Esto debería generar "testing123", pero no produce nada.

Funciona perfectamente en bash:

function testfun
{
    input="$(cat)"
    echo $input
}

echo testing123 | testfun
bug

Comentario más útil

Este problema, junto con la función grep predeterminada para grep , da como resultado bastantes problemas: si este problema no se va a solucionar pronto, el alias grep predeterminado probablemente debería eliminarse (o reemplazarse por una abreviatura, ¿tal vez?) para al menos minimizar las ocurrencias.

Usar cat como sugiere @milieu no parece solucionar el problema para mí, en Fish 2.3.1 (que me acabo de dar cuenta está un poco atrasada, pero es la versión empaquetada para Fedora 25)

Todos 21 comentarios

Puede utilizar la función "leer" como solución.

function t
    while read -l line
        echo $line
    end
end

Acabo de entender que en pescado no funciona, porque el stdin se canaliza a 'set' en lugar de 'cat'.

Este problema va más allá de simplemente "configurar" el funcionamiento de una determinada manera. La canalización en una función está arruinada. Y la E / S de terminal enviada a una función funciona, pero sigue siendo un poco extraño: parece almacenar en búfer la entrada y entregarla de una vez. Observa lo que sucede con esta función:

~> function meh
       cat
   end
~> # First, the way it's supposed to work.
~> # As input, we press the keys: a RET b RET control-D
~> cat
a
a
b
b
~> cat | cat
a
a
b
b
~> # Now...
~> meh
a
a
b
b
~> # So far so good, but...
~> cat | meh
a
b
^D
... um...
^D
control-D repeatedly does not work
try control-C
Job 1, “cat | meh” has stopped
~> fg
Send job 1, “cat | meh” to foreground
cat: stdin: Interrupted system call
~> jobs
jobs: There are no jobs
~> # Dear lord.
~> # For completeness...
~> meh | cat
a
b
aD
b
~> 

Además, cat | meh | cat comporta de la misma manera, al igual que cat | begin; cat; end .
Puedo decirles además que el "gato" que se queja de una llamada al sistema interrumpida en cat | meh es el primer "gato". Es decir:

~> cp /bin/cat mycat
~> ./mycat | meh
Job 1, “./mycat | meh” has stopped  #after control-C
~> fg
Send job 1, “./mycat | meh” to foreground
mycat: stdin: Interrupted system call

Así que ahí está. Obviamente, esto tiene que ver con la forma en que Fish llama a las funciones y cómo construye las tuberías en ellas. ¿Alguien sabe sobre esto?

Ok, lo encuentro corriendo
pbpaste | begin; cat; end
repetidamente en un caparazón de pescado fresco, con el portapapeles siendo "23 \ n", a veces simplemente imprime 23 de regreso, y a veces hace que el caparazón se bloquee, momento en el que control-C no puede hacer nada. Supongo que esto debe ser una condición de carrera de algún tipo. Oh chico.

Mientras tanto, parece que la señal SIGTTIN se envía al "mycat" en ./mycat | begin; cat; end :

     21    SIGTTIN      stop process         background read attempted from
                                             control terminal

Luego, de acuerdo con el manual GNU libc: "Un proceso no puede leer desde el terminal del usuario mientras se está ejecutando como trabajo en segundo plano. Cuando cualquier proceso en un trabajo en segundo plano intenta leer desde el terminal, se envían todos los procesos del trabajo una señal SIGTTIN ".

Entonces, parece que "mycat" se inicia en segundo plano, o se inicia y luego se coloca en segundo plano, cuando se canaliza a una especie de función de pescado. Quizás este conocimiento ayude.

Aparentemente, esto pone en segundo plano ambos lados de una tubería ... Pero al dar el comando fg extrae el proceso del fondo, lo que le permite funcionar como debería.

~ $ alias pjson='python -m json.tool | pygmentize -l json'
~ $ curl -u smoku -X GET -H "Content-Type: application/json" 'https://jira.......' | pjson
Job 4, 'curl -u smoku -X GET…' has stopped
~ $ fg
Enter host password for user 'smoku': ********
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   593    0   593    0     0   1372      0 --:--:-- --:--:-- --:--:--  1375
~ $ fg
{
    "expand": "renderedFields,names,schema,transitions,operations,editmeta,changelog",
    "id": "29874"
}

Un poco molesto que necesitaba crear pjson script de envoltura $PATH lugar de un alias simple ... :(

Para mi referencia, esto también es un error de openSUSE https://bugzilla.opensuse.org/show_bug.cgi?id=963548

¡Hurra! ¡Creo que encontré mi solución! Gracias al comentario de gustafj en el número 110 que explica la sintaxis de la tubería de pescado, se me ocurrió esto:

function line --argument-names n
    cat 1>| tail -n +$n | head -1
end

Este problema, junto con la función grep predeterminada para grep , da como resultado bastantes problemas: si este problema no se va a solucionar pronto, el alias grep predeterminado probablemente debería eliminarse (o reemplazarse por una abreviatura, ¿tal vez?) para al menos minimizar las ocurrencias.

Usar cat como sugiere @milieu no parece solucionar el problema para mí, en Fish 2.3.1 (que me acabo de dar cuenta está un poco atrasada, pero es la versión empaquetada para Fedora 25)

Parece que hay una diferencia entre la ejecución dentro del shell y desde la línea de comando:

(zsh)$ ./fish -c "read n | grep nothing"    
read> lol
(zsh)$ ./fish
(fish)$ read n | grep nothing
read> 
# Stuck forever, needs to kill the terminal. ^C, ^Z have no impact.

¿Quizás esto pueda ayudar a depurar el problema?

@layus : No, ese es el # 3805, un problema en el que los peces por sí mismos no pueden controlar la terminal.

_Creo que algo del comportamiento original en este sentido ha cambiado, el siguiente es con respecto a fish master / 3.0_

Hay dos problemas fundamentales que el pez se equivoca aquí, el primero es la función de almacenamiento en búfer / salida del bloque (estoy bastante seguro de que un shell moderno no almacenaría nada en ningún lugar) y el segundo es no poder encadenar correctamente la entrada / salida en un bloque. Hay mucha ambigüedad (o al menos espacio para diferencias de opinión aceptables) en cómo debería verse el comportamiento correcto en algunos casos de esquina, pero no creo que nadie defienda lo que hacen los peces actualmente como óptimo.

En general, tiene comandos externos (e incorporados que se tratan efectivamente de la misma manera, en general) que son fáciles: una entrada, dos salidas, una de las cuales se puede encadenar a un comando posterior, la otra debe redirigirse a un archivo o el tty. Pero los bloques y las funciones son complicados, ya que básicamente estás mapeando una entrada (ya que solo puede haber una) a una secuencia de (lo que eventualmente se expande) comandos externos o incorporados.

Dicho esto, no estoy de acuerdo con que el comportamiento actual sea incorrecto. (cat) no debe leer datos que se enviaron al comando en el que se ejecuta:

mqudsi<strong i="11">@ZBook</strong> /m/c/U/m/Documents> type testfun
testfun is a function with definition
function testfun
    set input (cat)
    printf "You said '%s'\n" $input
end
mqudsi<strong i="12">@ZBook</strong> ~/r/fish-shell> echo testing123 | testfun
hello
^D
You said 'hello'

Está canalizando la entrada al bloque, independientemente de si el conjunto consume la entrada, consume parte de la entrada o ignora la entrada por completo, cat es correcto para conectarse a /dev/tty para la entrada, que luego se pasa correctamente al shell para su sustitución en la línea de comandos. De hecho, hay / hubo (muchos) errores archivados contra este repositorio quejándose de casos en los que las "subcapas" _no_ se leían desde la terminal cuando se ejecutaban con algunos niveles de indirección. En mi humilde opinión, es bash el que está roto aquí, especialmente porque bash admite subcapas reales y ofrece asincronicidad aquí.

El único comportamiento roto, diría que proviene de casos en los que los comandos externos se inician en una función / bloque y no consumen completamente la entrada:

mqudsi<strong i="19">@ZBook</strong> /m/c/U/m/r/fish-shell> printf 'foo\nbar\n' | begin
                                        head -n1 | read -l line1
                                        head -n2 | read -l line2
                                        echo line1: $line1
                                        echo line2: $line2
                                    end
line1: foo
line2:

TBH estoy muy sorprendido pero esto funciona correctamente:

mqudsi<strong i="23">@ZBook</strong> /m/c/U/m/r/fish-shell> printf 'foo\nbar\n' | begin
                                        /bin/echo 'hi from echo'
                                        cat | read -z from_cat
                                        printf 'from_cat: "%s"' $from_cat
                                    end
hi from echo
from_cat: "foo
bar
"¶  

Y esto también es correcto:

mqudsi<strong i="27">@ZBook</strong> /m/c/U/m/r/fish-shell> printf 'foo\nbar\n' | begin
                                        cat | read -zl from_cat1
                                        cat | read -zl from_cat2
                                        printf 'from_cat1: "%s"\n' $from_cat1
                                        printf 'from_cat2: "%s"\n' $from_cat2
                                    end
from_cat1: "foo
bar
"
from_cat2: ""

Especialmente cuando se tiene en cuenta el plan de algún día introducir subcapas reales en peces con ejecución asincrónica, diría que el comportamiento de los peces con respecto al caso original reportado aquí es correcto. De hecho, me inclino a cerrar este tema por completo, a menos que alguien se oponga y pueda presentar un argumento convincente aquí.

Si bien el informe de error original no es válido en mi humilde opinión, los problemas planteados por @waterhouse son cat | meh informado.

mqudsi<strong i="8">@ZBook</strong> ~/r/fish-shell> cat | meh
a
a
b
b
^D
mqudsi<strong i="9">@ZBook</strong> ~/r/fish-shell>

Dicho esto, no estoy de acuerdo con que el comportamiento actual sea incorrecto. (cat) no debe leer datos que se enviaron al comando en el que se ejecuta:

¡Estoy muy en desacuerdo con eso!

cat es correcto para conectarse a / dev / tty para la entrada

Ésa es una cuestión de modelo mental. Yo diría que cat se conecta a "el stdin actual" para la entrada. Si la función o el bloque no se redirigen, ese es el tty. Si se redirige, ¡eso es todo! Entonces, conectarse a / dev / tty aquí sería incorrecto.

quejándose de casos en los que las "subcapas" no se leían desde la terminal cuando se ejecutaban con algunos niveles de indirección

Tenga en cuenta que se trataba de sustituciones de comandos "globales". Por ejemplo, ejecutar echo (fzf) en la línea de comandos. En ese caso, no hay stdin.

Entonces, lo que yo diría que funcionaría así:

echo | echo (cat) # from tty

begin
   echo | echo (cat) # from file
end < file

Hay un problema relacionado (# 1035) que pregunta sobre stderr en este caso, y que no se redirige. Lo cual fue un gran problema con la antigua función math , porque sucedió que presentaba una sustitución de comando dentro de ella, por lo que no se podía redirigir.

Esta es la parte estándar. Si una función hace un (cat) , ¿es realmente útil tener siempre esa lectura del tty? ¿O no podría simplemente usar </dev/tty en ese caso?

Pensamientos interesantes.

Supongo que se reduce a si los paréntesis denotan una sustitución simple (es decir, "simule que el contenido de los paréntesis estaba en la línea anterior, ejecútelos hasta completarlos, almacene el resultado en una variable y sustituya la variable aquí") o si ' re (actualmente roto) subcapas. Pensé que el consenso era que al pescado le falta el soporte adecuado de la subcapa, pero la intención siempre ha sido arreglar eso "en algún momento".

Si es lo primero, entonces sí, estoy de acuerdo, el comportamiento actual está roto porque si mueve el contenido de los paréntesis a una línea diferente, ciertamente debería leer desde la entrada que se redirige al bloque.

Pero las subcapas son un concepto mucho más poderoso que ese, y le permiten hacer cosas que no son posibles con la sustitución de comandos y crear scripts mucho más receptivos y capaces. Si bien es técnicamente posible conectar lo que se ingresa en el bloque al stdin de un comando ejecutado en una subcapa, creo que sería incompatible con el modelo mental allí .

si los paréntesis denotan una sustitución simple (es decir, "simule que el contenido de los paréntesis estaba en la línea anterior, ejecútelos hasta completarlos, almacene el resultado en una variable y sustituya la variable aquí") o si están (actualmente rotos) subcapas .

No creo que estos términos estén definidos con suficiente claridad como para ser de mucha utilidad aquí.

Para mí, todo se reduce a lo que es más natural, más típico y más útil.

Leer desde la terminal es ciertamente útil y, a veces, desea leer desde la terminal aunque tenga otro stdin (por ejemplo, fzf hace básicamente esto exclusivamente).

Pero creo que leer desde stdin es mucho más típico, especialmente considerando que los usos no interactivos no leerán desde tty en absoluto. Y dado que todavía es posible leer desde tty (a través de esa redirección </dev/tty ), parece correcto dejar eso como la opción secundaria.

El hecho de que no haya nada opuesto a </dev/tty en el modelo que sugiero me está haciendo reconsiderar mi posición.

Puede que no sea lo suficientemente profundo como para entender la discusión por completo. Pero necesito resolver algo y me pregunto si necesito un script bash para resolverlo.

Es básicamente una tarea muy simple: quiero canalizar stdout desde (z) cat a través de pv a un cli de mysql (básicamente para restaurar una copia de seguridad) y como no quiero ingresar la cadena de conexión, quiero usar una función para ello :

function mysqlenv --description connect to mysql server using config from .env
  mysql -u (getEnv DB_USERNAME) -p(getEnv DB_PASSWORD) (getEnv DB_DATABASE)
end

Primero estaba seguro de que esto funcionaría porque es obvio que stdin para un comando es stdout del comando en el lado izquierdo, pero ahora estoy confundido. Ok, mysqlenv no es un comando, es una función. Ahora estoy aquí leyendo mucho texto y mucho de "esto debería funcionar" pero nada funciona.

Lo que probé:

  • cat -|mysql... sin salida; mysql no obtiene entrada; ctr + c existe mysql; la tubería se está ejecutando en segundo plano
  • mysql... <&0 sin salida; mysql no obtiene entrada; ctr + c existe mysql; la tubería se está ejecutando en segundo plano
  • set input (cat); mysql... sin salida; mysql no obtiene entrada; ctr + c existe todo; nada queda en el fondo
  • read -z|mysql... sin salida; mysql no obtiene entrada; ctr + c imprime ^c

Nuevamente mi símbolo del sistema: zcat some_backup.sql.gz|pv -s (zsize some_backup.sql.gz)|mysqlenv . Muestra el estado de la tubería cuando se usa directamente con mysql (sin una función de pez en el medio), por lo que debería funcionar.

Entonces, ¿cómo pasar stdin de la función a stdin de un comando dentro de la función?

No diga que tengo que volver a conectarme para cada línea a través de while read... . Puede funcionar, pero no es una solución, ya que es demasiado lento para trabajar.

@tflori : Mucho más simple. Simplemente deje el comando como está, sin redirecciones. El problema no es con los comandos directamente en la función. Algo como

function foo
    cat
end

trabajos. El cat obtiene stdin como debería.

Lo que no ocurre es cuando está en una sustitución de comando, ahí es cuando se detecta este error.

@faho, ¿ eso significa que la función inicial debería funcionar? pero no es así. tal vez mi versión esté desactualizada? Estoy usando 2.7.1 actualmente

tal vez mi versión esté desactualizada? Estoy usando 2.7.1 actualmente

@tflori : Sí, querrás 3.0.2.

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