
cd
親プロセスで使用されるパスを返す対話型スクリプトがあります。このように:
$ cd $(myscript)
スクリプトの実行中に使用したいと思いますless
。残念ながら、コマンドの置換中に を使用することはうまくless
いかないようです。
$ echo $(less <<< 'some text') # Not working
some text
だから私の質問は:なぜ動作しないのですか?解決策はありますか?
スクリプトの実行中に対話型ヘルプ画面を表示しようとしています。このスクリプトをコマンド置換に入れる必要があります。これは、親プロセスで作成されたパスにCDを移動する唯一の方法であるためです。より良い方法があるかもしれませんが、これが最善の選択です。
答え1
echo $(somecmd)
通常、すべてのsomecmd
.の場合、出力はsomecmd
の引数に展開され、その引数を取得echo
しecho
て出力に印刷します。通常は直接実行できますsomecmd
。
ワードセパレータとワイルドカードの2つの違いは一般的です。echo $(somecmd)
スペースを圧縮し、ファイル名glob()のように見えるすべての項目を展開します*.txt
。しかし、もちろん、これは単に実行するかsomecmd
引用echo "$(somecmd)"
符で実行するときには発生しません。それ最後の改行文字を除くすべての項目を削除します。拡張バックスラッシュをエスケープするecho
こともできます。
less
の目的は次のとおりです。インタラクティブファイルを参照するか、端末がほとんど必要なパイプ入力を実行します。コマンド置換で実行すると、 の出力がless
パイプに接続され、その動作が . cat
(マンページで正確な動作に関する言及が見つからないようです)
これで、コマンドオーバーライドで実行され、ユーザーがいくつかの出力を参照できるようにし、コマンド置換で別のテキストを返すスクリプトが必要な場合は、リダイレクトをクリエイティブに使用できるようになります(mosvyの説明)。
$ cat myscript
#!/bin/bash
echo this is the output
cat >&2 <<EOF
you can
browse this
with less
EOF
$ foo=$( ./myscript 2> >(less > /dev/tty))
スクリプトの標準出力はコマンドオーバーライドに移動し、エラー出力はに設定されるために設定さless
れfoo
ますthis is the output
。foo
少なくともless
。
さらに、これらの実行はless
ジョブ制御を混乱させるので、実行中にCtrl-Cを押すと奇妙な動作が発生する可能性があります。
ここでは一時ファイルを使用することをお勧めします。結果をパラメータ(たとえば)myscript
というファイルに書き込み、次のコマンドを実行します。echo "$result" > "$1"
tmp=$(mktemp)
myscript "$tmp"
cd "$(cat "$tmp")"
rm "$tmp"
あるいは、他の対話型プログラムをmyscript
一般的な方法で起動することができ、タスクless
制御に問題がないはずです。
答え2
(trap : INT; echo "$(less <<< 'some text' >/dev/tty; echo done)")
less
cat
コマンドの置き換え(標準出力がパイプの場合)に使用されるときなど、標準出力がttyでない場合は、何か(非)クールになります[1]。
対話型bashでテストすると(ジョブ制御はデフォルトで有効になっています)、(...)
サブシェルはコマンドが端末で正しいフォアグラウンドジョブの一部として実行されることを確認します。そうしないと、次のコマンドを使用してジョブを一時停止して終了することがless
できない可能性があります。誤った行動は異なる方法で起こります[2]。^Z
^C
これにより、trap : INT
サブシェルはaを無視し、^C
その構成をそのサブシェルに渡さないようにします。
コマンドがシェルスクリプトの一部である場合、すべてのプロセスは同じプロセスグループ/タスクの一部として実行されますが、(...)
トラップの範囲を制限することはまだ役に立ちますINT
。
[1]標準出力がttyでない場合は、きれいにエスケープされたバイナリデータを印刷するためにも使用できません。
$ printf '\xee' | less -FXR
<EE>
$ printf '\xee' | less -FXR | cat
�$
[2]起こり得ることが多く、すべて悪い。例えば、
$ ls -d $(less <<<'some text' >/dev/tty; pwd)
bash
別のプロセスをフォークしてバイナリを実行し、プロセスの置き換えを子プロセスとしてls
実行します。$(...)
今後別のプロセスグループ/タスクに移動し、バイナリを実行します。
^Z
内側を押すとless
正常に処理されますが、停止less
できないか(シェルとその操作がless
セッションリーダーの場合)、停止するだけでless
親プロセスは停止しません。
^C
inside を押すとless
捕捉され処理されますが、less
a メインシェル(ターミナルのフォアグラウンドジョブ)に転送され、bash の readline および race だけでSIGINT
なく次のプロンプトに戻ります。less
端末属性の変更はお互いを認識せず、完全な混乱を招きます。
ノート
これらの内容はすべて以下に適用されます。どのプログラムは例だけでなく、コマンドの置き換えによって実行されます$(less ...)
。
$ cat >foo <<'EOT'; chmod 755 foo
t=$(mktemp)
vi "$t" </dev/tty >/dev/tty 2>&1
echo "$t"
EOT
$ cat $(./foo)
# ^Z doesn't work in vi