manipulação de substituição de comandos em peixes vs. outras shells (sh, bash, zsh)

5

O programa mc ( Midnight Commander ) não se destina a ser usado para substituição de comandos, mas eu gostaria de sabe por que diferentes shells se comportam diferentemente quando este programa (e parece que outros curses programas em geral) são usados como um alvo de substituição de comandos.

No fish shell , a emissão do comando abaixo imprimirá a string "Não é possível obter configurações do terminal: ioctl inadequado para o dispositivo (25) \ n \ n ".

echo (mc) # fish command substitution syntax

Outra coisa interessante a notar é que, após o retorno desse comando, você pode emitir jobs para ver se o processo mc foi suspenso.

O comando equivalente em sh, bash e zsh trava o shell, e por travar quero dizer que não posso matar o comando ou suspendê-lo usando C-z / C-c. A única maneira de recuperar-me do comando é matar meu processo de shell e reiniciá-lo (a partir de um shell diferente).

echo $(mc) # hangs in sh, bash, zsh

Por que a casca do peixe não está pendurada? Como ele lida com curses ou substituição de comandos ou etc. de forma diferente para produzir esse comportamento? Eu sinto que isso é importante porque pode ser uma propriedade desejável para outras conchas; nenhum comando deve ser capaz de renderizar um shell totalmente inoperável por acidente.

EDIT: Outra maneira de responder a essa pergunta seria mostrar por que o programa a seguir é suspenso quando usado como um destino de substituição de comando no fish shell. Como mc , ele usa curses, mas é modificado para reabrir stdin quando detecta stdin não é um tty. Isso permite que o modo curses seja usado em todos os shells, exceto em fish.

#define _XOPEN_SOURCE
#include <ncurses.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    // start curses mode
    SCREEN* s = NULL;
    FILE* out = stdout;
    if(!isatty(fileno(stdout))) {
        out = fopen("/dev/tty", "w");
        // Should really test 'out' to make sure that worked.
        setbuf(out, NULL);
    }
    // Here, we don't worry about the case where stdin has been
    // redirected, but we could do something similar to out
    // for input, opening "/dev/tty" in mode "r" for in if necessary.
    s = newterm(NULL, out, stdin);

    printw("test");
    getch();

    endwin(); // end curses mode
    delscreen(s);
    puts("/home/matt");
    return 0;
}

Veja esta pergunta para obter mais informações: link . Este código foi uma solução postada na minha pergunta original no Stackoverflow. A solução funciona para todas as conchas, mas para peixes.

EDIT: Tentei encontrar mais informações iniciando o peixe no gdb. Usou a seguinte sequência de comando gdb e obteve a seguinte saída:

(gdb) break main
Breakpoint 1 at 0x41fe70: file fish.cpp, line 417.
(gdb) run -c echo (mc)
Starting program: /home/matt/builds/fish-shell/fish -c echo (mc)
Cannot get terminal settings: Inappropriate ioctl for device (25)

O depurador pausa aqui e não produz mais saída. Isso é estranho porque o breakpoint no main nunca bateu. O shell de peixe precisa analisar seus argumentos de linha de comando antes de fazer a substituição do comando, mas não tenho certeza de como o encadeamento afeta a observação disso no depurador.

    
por Matthew Mellott 04.07.2013 / 14:10

1 resposta

1

Ok, acho que tenho uma pista do que está acontecendo.

O comportamento que você está observando em zsh e bash ao executar echo $(mc) é causado por mc .

Quando você executa mc normalmente, ele não reage quando a tecla Ctrl + c é pressionada, pois ignora SIGINT . A maneira de finalizar mc é pressionando F10 e Enter.

Quando você executa echo $(mc) , a entrada vai para o processo mc , então não é de admirar que quando você pressionar Ctrl + c nada acontecerá, porque mc ignora SIGINT . Mas quando você executar echo $(mc) e pressionar F10 e Enter, ele reagirá. (Quando eu, em seguida, pressionar F10 e Enter novamente ele realmente sai; ele deve sair na primeira tentativa, mas eu não tenho idéia do por que isso não acontece.)

A partir disso, deduzo que o Midnight Commander está funcionando normalmente, mas a saída dele é colocada no buffer do shell, para que possa ser usada mais tarde por echo . Algo que devemos considerar normal.

Além disso, você acha que bash e zsh estão pendurados, mas eu diria que eles não estão pendurados, mas aguardando o retorno do comando echo . Mas echo só pode retornar quando mc retorna, o que ocorre somente quando F10 e Enter são pressionados. Com isso, também podemos explicar o que acontece quando você pressiona Ctrl + z . Pressionando a combinação mc vai dormir como se você tivesse corrido mc normalmente e echo ainda estivesse esperando o mc dormindo.

Então tudo é comportamento normal. Exceto pelo que o peixe faz. peixe parece iniciar comandos executados com echo ($command) no plano de fundo. Isso faz sentido, já que tal comando normalmente não precisa de nenhuma entrada. Por que e como eu não tenho resposta. Mas você pode ver que ele é executado em segundo plano quando você entra

echo (mc)
jobs
    
por 10.07.2013 / 17:42