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

なぜ魚の皮がぶら下がっていないのですか?この動作を生成するために、呪いや命令の置換などをどのように異なる方法で処理しますか?私はこれが他のシェルが持っている望ましい属性である可能性があるので重要だと思います。どのコマンドも誤ってシェルが完全に機能しないようにしてはいけません。

編集する:この質問に答えるもう1つの方法は、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

おすすめ記事