프로그램 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 셸에서 명령 대체 대상으로 사용될 때 다음 프로그램이 중단되는 이유를 설명하는 것입니다. 와 마찬가지로 mc
curses를 사용하지만 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을 누르고 엔터를 치는 것입니다.CtrlcSIGINT
mc
실행하면 echo $(mc)
입력이 프로세스로 들어가므로 +를 mc
누르면 무시되기 때문에 아무 일도 일어나지 않는 것이 당연 합니다 . 그러나 실행 하고 F10과 Enter를 누르면 반응합니다. (F10과 Enter를 다시 누르면 실제로 종료됩니다. 첫 번째 시도에서 종료되어야 하는데 왜 종료되지 않았는지 모르겠습니다.)Ctrlcmc
SIGINT
echo $(mc)
이 사실로부터 나는 Midnight Commander가 정상적으로 실행되지만 그 출력은 나중에 읽을 수 있도록 쉘 버퍼에 저장된다는 것을 추론했습니다 echo
.
echo
또한 bash와 zsh가 멈췄다고 생각하지만 멈춘 것이 아니라 명령이 반환되기를 기다리고 있다고 말하고 싶습니다 . 그러나 F10과 Enter를 눌렀을 때만 돌아올 echo
수 있습니다 . 이 방법으로 +를 누르면 무슨 일이 일어나는지 mc
설명할 수도 있습니다 . 정상적으로 달리고 있지만 여전히 절전 모드를 기다리는 경우와 마찬가지로 키 조합을 눌러 절전 모드로 들어갑니다 .Ctrlzmc
mc
echo
mc
따라서 모든 것이 정상적인 동작입니다. 물고기의 행동을 제외하고. Fish는 echo ($command)
백그라운드에서 실행되는 명령을 실행하는 것으로 보입니다 . 이러한 명령에는 일반적으로 입력이 필요하지 않기 때문에 이는 의미가 있습니다. 왜, 어떻게에 대한 답이 없습니다. 하지만 입력한 후에는 백그라운드에서 실행되는 것을 볼 수 있습니다.
echo (mc)
jobs