zshは最後に実行したプログラムの標準出力にアクセスできますか?


14

私はよく、findまたはlocateパスについて調べるために使用します。

(~) locate foobar.mmpz
/home/progo/lmms/projects/foobar.mmpz

次のステップは、多くの場合、ファイルを開くか、そうでなければファイルを操作することです。上記のような幸せな場合、私はこれを行うことができます:

(~) ls `!!`
ls `locate foobar.mmpz`
/home/progo/lmms/projects/foobar.mmpz

しかし、出力の行が多数ある場合、誰もあまり幸せではありません。その一部は、パスまたはそのようなものではないかもしれません。その上、無駄になる可能性のあるコマンドを再実行することもそれほどエレガントではありません。

zshを接続して、後で操作するためにstdoutを配列に保存する方法はありますか?結局、ストリームをユーザーにリダイレクトするのはシェルの仕事です。私は、最初のN行と最後のN行を変数に保存して、すぐに後で使用できるように考えています、など$?など。

[OK]を:これはかなりクールです/unix//a/59704/5674。各実行行の後にこの種のキャプチャをリグするためのzshのノウハウ(およびコードをzshに移植する)について質問しています。


ストリームをユーザーにリダイレクトするのは、実際にはシェルの仕事ではありません。アプリケーションは出力を端末デバイスに書き込みますが、シェルはそれに関与しません。
ステファンシャゼル

@StephaneChazelas、しかし、ユーザーのリクエストごとにストリームをファイルにリダイレクトするのはシェルの仕事です。また、stderrを赤で標準出力から分離するzshのレシピもあります。これは、ストリーミングの問題におけるシェルの役割を示していると思います。
unperson325680 14

はい、screenまたはscriptandおよびprecmdおよびpreexecフックを使用して実行できます。
ステファンシャゼル14

回答:


6

ほとんどの端末エミュレーターでは、画面からの出力をキャプチャする機能はありません。xterm(「リファレンス」ターミナルエミュレータ)の作成者は、実装が難しいと述べていたことを思い出すようです。それが可能であったとしても、シェルは最後のプロンプトがどこにあったかを追跡しなければなりません。

したがって、xtermのマウスやScreenのキーボードを使用したコピーペーストなど、端末固有の手動メカニズムを使用しない限り、コマンドを再度実行する必要はありません。

シェルがコマンドの出力を自動的にキャプチャすることは非常に非現実的です。なぜなら、シェルは、複雑な端末とユーザーの対話があるコマンドと、印刷可能な文字を単に出力するコマンドを区別できないからです。

コマンドを再実行して、その出力をキャプチャできます。それぞれにさまざまな方法があります。コマンドを再実行するには、次を使用できます。

  • !! 履歴置換—入力が最も便利です。
  • fc -e -、関数で使用できます。

出力をキャプチャするには、コマンド置換、または次のような関数を使用できます。

K () {
  lines=("${(f@)$(cat)}")
}
!! |K

これにより、lines配列はパイプで渡されたコマンドの出力に設定されます。


だからそれ。私は今、完全な自動化アプローチはそのままでは難しすぎるという良い説明に照らして、2番目に良いことはKあなたのようなものだと気づきました。
unperson325680 14

3

出力の最終行をと呼ばれる変数に入れるための最初のカットを次に示します$lastline

precmd () {                                                                                                                                                                                                        
    exec 2>&- >&-
    lastline=$(tail -1 ~/.command.out) 
    sleep 0.1   # TODO: synchronize better
    exec > /dev/tty 2>&1
}

preexec() {
    exec > >(tee ~/.command.out&)
}

これは、zshのpreexecフックを使用して実行exectee、コマンドのstdoutのコピーを保存します。次にprecmd、保存された出力を読み取り、stdoutを復元して、プロンプトを表示する端末のみにします。

しかし、まだいくつかの作業が必要です。例えば、stdoutがもはやなどの端末、プログラムされていないため、vimless正常に動作しません。

これらの質問にはいくつかの有用な関連情報があります。


はい、おそらく100%自動化されたアプローチは機能しません。execコードには多くの呼び出しがありますが、コマンドは複数回実行されていますか、または特別なセマンティクスに捕らわれていますか?
unperson325680 14

execプログラム名がなければ、リダイレクトを設定するだけです。
ミケル14

2

これを行うには、結果をteeにパイプするだけで、出力をファイルに保存すると同時に表示します。

したがって、たとえば、これを行うと、通常のように出力が表示されますが、ファイルにも保存されます /tmp/it

locate foobar.mmpz | tee /tmp/it

次に、そのファイルをcatし、grepして、例えば、

cat /tmp/it | grep progo | grep lms

それを使用するには、これを行うことができます:

vi $(!!)


2

私はこの中途半端な解決策を思いつきました:

alias -g ___='"$(eval "$(fc -ln -1)" | tail -n 1)"'

これにより___、コマンドラインの任意の時点で書き込むことができます。前のコマンドが再実行され、___出力の最後の行に置き換えられます。使用例:

$ touch foo bar baz
$ ls -1
bar
baz
foo
$ vim ___

最後のコマンドはに展開されvim fooます。

これにはシャープなエッジがあります!

  • ___コマンドに含めるが、前のコマンドにもが含まれている___場合、シェルはしばらくの間奇妙な状態でハングします。Ctrl-を使用すると、この状態をすぐに抜けることができますC

  • あなたはまた、押すことができませんTab拡大に___あなたができるように、!$そして他の構造。

  • 一部のコマンドは、「通常」実行される場合とパイプに接続される場合に異なる出力を表示します。(の出力を比較lsしてls | cat。)によってトリガコマンドがいる場合___、あなたが予想より別のコマンドを実行してしまうかもしれないが、これらの一つです。

  • そしてもちろん、最後の行以外の出力行で何かをしたい場合、これは役に立ちません。

名前を選んだのは___、引数としてではなく、コマンドラインの単語として含めたくなかったからです。別の名前を選択することもできますが、誤って展開される可能性のあるものを選択しないように注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.