
プログラム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
なぜ魚の皮がぶら下がっていないのですか?この動作を生成するために、呪いや命令の置換などをどのように異なる方法で処理しますか?私はこれが他のシェルが持っている望ましい属性である可能性があるので重要だと思います。どのコマンドも誤ってシェルが完全に機能しないようにしてはいけません。
編集する:この質問に答えるもう1つの方法は、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