Fish 및 기타 쉘(sh, bash, zsh)에서 명령 대체 처리

Fish 및 기타 쉘(sh, bash, zsh)에서 명령 대체 처리

프로그램 mc(자정 사령관)은 명령 대체에 사용하기 위한 것이 아니지만, 이 프로그램(종종 다른 Curs 프로그램처럼 보임)을 명령 대체 대상으로 사용할 때 왜 다른 쉘이 다르게 동작하는지 궁금합니다.

내부에생선 껍질, 다음 명령을 실행하면 "터미널 설정을 얻을 수 없습니다: 장치(25)에 대한 부적절한 ioctl\n\n"이라는 문자열이 인쇄됩니다.

echo (mc) # fish command substitution syntax

주목해야 할 또 다른 흥미로운 점은 이 명령이 반환된 후 명령을 실행하여 프로세스가 중단되었는지 jobs확인할 수 있다는 것입니다.mc

sh, bash 및 zsh의 해당 명령은 셸을 정지시키며, 정지는 Cz/Cc를 사용하여 명령을 종료하거나 정지할 수 없음을 의미합니다. 명령에서 복구할 수 있는 유일한 방법은 셸 프로세스를 종료하고 (다른 셸에서) 다시 시작하는 것입니다.

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

왜 생선 껍질이 매달리지 않나요? 이 동작을 생성하기 위해 저주 또는 명령 대체 등을 어떻게 다르게 처리합니까? 나는 이것이 다른 쉘이 갖고 있는 바람직한 속성일 수 있기 때문에 중요하다고 생각합니다. 어떤 명령도 실수로 쉘이 완전히 작동하지 않게 해서는 안 됩니다.

편집하다:이 질문에 대답하는 또 다른 방법은 Fish 셸에서 명령 대체 대상으로 사용될 때 다음 프로그램이 중단되는 이유를 설명하는 것입니다. 와 마찬가지로 mccurses를 사용하지만 stdin이 tty가 아닌 것을 감지하면 stdin을 다시 열도록 수정되었습니다. 이렇게 하면 물고기를 제외한 모든 껍질에서 저주 모드를 사용할 수 있습니다.

#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;
}

자세한 내용은 이 질문을 참조하세요.https://stackoverflow.com/questions/17450014/ncurses-program-not-working-rightly-when-used-for-command-substitution. 이 코드는 제가 Stackoverflow에 게시한 원래 질문에 대한 솔루션입니다. 이 솔루션은 생선을 제외한 모든 껍질에 적용됩니다.

편집하다:gdb에서 Fish를 시작하여 더 많은 정보를 찾아보세요. 다음 gdb 명령 시퀀스를 사용하여 다음 출력을 얻습니다.

(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)

디버거가 여기서 일시 중지되고 더 이상 출력을 생성하지 않습니다. 메인의 중단점은 결코 적중되지 않기 때문에 이것은 이상합니다. Fish 셸은 명령 대체를 수행하기 전에 해당 명령줄 인수를 구문 분석해야 하지만 스레딩이 디버거에서 이를 관찰하는 데 어떤 영향을 미치는지 잘 모르겠습니다.

답변1

좋아, 무슨 일인지 알 것 같아.

실행 시 zsh 및 bash에서 관찰되는 동작 echo $(mc)mc.

정상적으로 실행하면 mc무시하기 때문에 +를 눌러도 반응하지 않습니다. 종료하는 방법은 F10을 누르고 엔터를 치는 것입니다.CtrlcSIGINTmc

실행하면 echo $(mc)입력이 프로세스로 들어가므로 +를 mc누르면 무시되기 때문에 아무 일도 일어나지 않는 것이 당연 합니다 . 그러나 실행 하고 F10과 Enter를 누르면 반응합니다. (F10과 Enter를 다시 누르면 실제로 종료됩니다. 첫 번째 시도에서 종료되어야 하는데 왜 종료되지 않았는지 모르겠습니다.)CtrlcmcSIGINTecho $(mc)

이 사실로부터 나는 Midnight Commander가 정상적으로 실행되지만 그 출력은 나중에 읽을 수 있도록 쉘 버퍼에 저장된다는 것을 추론했습니다 echo.

echo또한 bash와 zsh가 멈췄다고 생각하지만 멈춘 것이 아니라 명령이 반환되기를 기다리고 있다고 말하고 싶습니다 . 그러나 F10과 Enter를 눌렀을 때만 돌아올 echo수 있습니다 . 이 방법으로 +를 누르면 무슨 일이 일어나는지 mc설명할 수도 있습니다 . 정상적으로 달리고 있지만 여전히 절전 모드를 기다리는 경우와 마찬가지로 키 조합을 눌러 절전 모드로 들어갑니다 .Ctrlzmcmcechomc

따라서 모든 것이 정상적인 동작입니다. 물고기의 행동을 제외하고. Fish는 echo ($command)백그라운드에서 실행되는 명령을 실행하는 것으로 보입니다 . 이러한 명령에는 일반적으로 입력이 필요하지 않기 때문에 이는 의미가 있습니다. 왜, 어떻게에 대한 답이 없습니다. 하지만 입력한 후에는 백그라운드에서 실행되는 것을 볼 수 있습니다.

echo (mc)
jobs

관련 정보