Bashの最後のコマンドからの出力を再利用する


回答:


184

を使用$(!!) して、最後のコマンドの出力を再計算できます(再利用できません)。

!!独自の実行の最後のコマンドを実行します。

$ echo pierre
pierre
$ echo my name is $(!!)
echo my name is $(echo pierre)
my name is pierre

9
$(your_cmd)バックティックを使用することで、入力する手間を省くことができます`your_cmd`。GnuBashのマニュアルによれば、機能は同じです。もちろん、これは@memecsから出された警告の対象でもあります

実際には、コマンドの出力は確定的であるため、再計算に悩まされることはありません。git diff $(!!)前のコマンドがfind呼び出しであった場所などを実行したい場合に、これは確かに役立ちます。
Sridhar Sarnobat

どうやら$()、バッククォートの代わりに使用するのに十分な理由があります。しかし、おそらく睡眠を失うものは何もない。github.com/koalaman/shellcheck/wiki/SC2006
Michael Crenshaw

1
@ user2065875バッククォートはまだBashで機能しますが、の代わりに非推奨になりました$()
kurczynski

87

答えはいいえだ。Bashは、メモリ上のパラメータやブロックに出力を割り当てません。また、Bashへのアクセスは、許可されたインターフェース操作によってのみ許可されています。Bashの個人データは、ハッキングしない限りアクセスできません。


2
すべてのコマンドの前に実行されるカスタムbash 'ミドルウェア'関数を使用して、結果の出力を内部クリップボードとして機能するもの(たとえば、BASH_CLIPBOARD)に保存することは可能ですか?
Pat Needham、2018

@PatNeedhamわかりません。ロード可能なモジュールを確認してください。作成できるかどうか確認してください。
konsolebox

11

これを行う1つの方法は、次のものを使用することですtrap DEBUG

f() { bash -c "$BASH_COMMAND" >& /tmp/out.log; }
trap 'f' DEBUG

最近実行されたコマンドのstdoutとstderrは、 /tmp/out.log

唯一の欠点は、コマンドを2回実行することです。1回目は出力とエラーをリダイレクトし/tmp/out.log、もう1回は通常です。おそらく、この動作を防ぐ方法もいくつかあります。


10
だから私がタイプするrm -rf * && cd ..と、現在のディレクトリだけでなく親ディレクトリも消去されますか?このアプローチは私にとって非常に危険に思われます
phil294

1
この操作を元に戻すにはどうすればよいですか?
Kartik Chauhan 2018年

5
@KartikChauhan:Just dotrap '' DEBUG
anubhava

7

Macを使用していて、変数に書き込む代わりに出力をクリップボードに保存してもかまわない場合は、回避策としてpbcopyとpbpasteを使用できます。

たとえば、これを行う代わりに、ファイルを見つけて、その内容を別のファイルと比較します。

$ find app -name 'one.php' 
/var/bar/app/one.php

$ diff /var/bar/app/one.php /var/bar/two.php

あなたはこれを行うことができます:

$ find app -name 'one.php' | pbcopy
$ diff $(pbpaste) /var/bar/two.php

/var/bar/app/one.php最初のコマンドを実行すると、文字列はクリップボードにあります。

ちなみに、pb in pbcopyとはpbpaste、クリップボードの同義語であるペーストボードの略です。


1
Linuxの場合 $ find app -name 'one.php' | xclip $ diff $(xclip -o) /var/bar/two.php
si-mikey 2018年

興味深いことに、pbpasteコマンド置換と一緒に使用することは考えていませんでした。
Sridhar Sarnobat

最初と後でそれが非効率的であるとわかった場合、どうすれば2番目のオプションで再実行せずに計算時間を節約できますか?
NelsonGon

4

anubhavaの回答に触発されました。これは、各コマンドを2回実行するため、実際には受け入れられないと思います。

save_output() { 
   exec 1>&3 
   { [ -f /tmp/current ] && mv /tmp/current /tmp/last; }
   exec > >(tee /tmp/current)
}

exec 3>&1
trap save_output DEBUG

このように、最後のコマンドの出力は/ tmp / lastにあり、コマンドは2回呼び出されません。


1
私はこれを見つけた一つの欠点は、あなたのコマンドのいずれもが、彼らはあなたのようなユーティリティのために働いてカラーコードを取得するために特別な注意を必要とすることを意味する、もはやTTYで稼働していると思うんですgrepgit diffけれども、とにかく1
マーティ・ニール

2

konsoleboxが言ったように、bash自体にハッキングする必要があります。ここで 1はこれを実現する方法を上のかなり良い例です。stderredリポジトリ(実際にはstdoutを色付けするためのもの)は、それを構築する方法についての指示を提供します。

内部でいくつかの新しいファイルディスクリプタの定義:私はそれを試した.bashrcように

exec 41>/tmp/my_console_log

(数値は任意です)stderred.cそれに応じて変更して、コンテンツもfd 41に書き込まれるようにします。これは一種の機能ですが、NULバイトのロード、奇妙なフォーマットを含み、基本的にバイナリデータであり、読み取り不可能です。たぶん、Cをよく理解している人なら、それを試してみることができるでしょう。

その場合、最後に印刷された行を取得するために必要なものはすべてですtail -n 1 [logfile]


1

ええ、同意するたびに余分な行を入力する理由。戻り値を入力にリダイレクトできますが、入力(1>&0)への出力はできません。また、関数ごとに同じ関数を何度も記述したくありません。

ファイルをどこにもエクスポートせず、ローカルでのみ使用する場合は、ターミナルで関数宣言をセットアップできます。~/.bashrcファイルまたはファイルに関数を追加する必要があり~/.profileます。後者の場合、あなたは有効にする必要がありますRun command as login shellからEdit>Preferences>yourProfile>Command

簡単な関数を作成します。

get_prev()
{
    # option 1: create an executable with the command(s) and run it
    echo $* > /tmp/exe
    bash /tmp/exe > /tmp/out

    # option 2: if your command is single command (no-pipe, no semi-colons), still it may not run correct in some exceptions
    #echo `$*` > /tmp/out

    # return the command(s) outputs line by line
    IFS=$(echo -en "\n\b")
    arr=()
    exec 3</tmp/out
    while read -u 3 -r line
    do
        arr+=($line)
        echo $line
    done
    exec 3<&-
}

メインスクリプト:

#run your command:
cmd="echo hey ya; echo hey hi; printf `expr 10 + 10`'\n' ; printf $((10 + 20))'\n'"
get_prev $cmd
#or simply
get_prev "echo hey ya; echo hey hi; printf `expr 10 + 10`'\n' ; printf $((10 + 20))'\n'"

Bashは以前のスコープ外でも変数を保存します。

#get previous command outputs in arr
for((i=0; i<${#arr[@]}; i++)); do echo ${arr[i]}; done

1

非常にシンプルなソリューション

私が長年使ってきたもの。

スクリプト(.bashrcまたはに追加.bash_profile

# capture the output of a command so it can be retrieved with ret
cap () { tee /tmp/capture.out}

# return the output of the most recent command that was captured by cap
ret () { cat /tmp/capture.out }

使用法

$ find . -name 'filename' | cap
/path/to/filename

$ ret
/path/to/filename

私は| capすべてのコマンドの最後に追加する傾向があります。このようにして、実行速度の遅いコマンドの出力に対してテキスト処理を実行したい場合、いつでもそれを取得できますres


ポイント何cat -cap () { cat - | tee /tmp/capture.out}ここには?いcap () { tee /tmp/capture.out }、私が欠けている任意のしゃっくり招きますか?
ワトソン

1
@ワトソン良い点!なぜそこにあるのか、おそらく癖があるのか​​わかりません。cat - | cat - | cat -面白くするためだけに、あらかじめ追加しておくべきでしょうか?tested本当にスパンドレルであることを確認するためにテストしたら、修正します
コナー

0

あなたがこれを何のために必要としているのか正確にはわからないので、この答えは関係がないかもしれません。コマンドの出力はいつでも保存できますがnetstat >> output.txt、それはあなたが探しているものではないと思います。

もちろんプログラミングオプションもあります。コマンドを実行した後、プログラムで上記のテキストファイルを読み取って変数に関連付けるだけです。選択した言語であるRubyでは、 'backticks'を使用してコマンド出力から変数を作成できます。

output = `ls`                       #(this is a comment) create variable out of command

if output.include? "Downloads"      #if statement to see if command includes 'Downloads' folder
print "there appears to be a folder named downloads in this directory."
else
print "there is no directory called downloads in this file."
end

これを.rbファイルに貼り付けて実行ruby file.rbすると、コマンドから変数が作成され、操作できるようになります。


9
「わからないあなたはこれを必要としているまさに」まあ、言ってます(これにより、I平均I)だけで、長時間のスクリプトを実行した出力を検索したい、と愚か実行する前に出力をリダイレクトするのを忘れました。今度は、スクリプトを再実行せずに愚かさを解消しようと思います。
jscs 2017

0

すぐに実装する時間がないと思っています。

しかし、次のようなことをしたらどうなるでしょう。

$ MY_HISTORY_FILE = `get_temp_filename`
$ MY_HISTORY_FILE=$MY_HISTORY_FILE bash -i 2>&1 | tee $MY_HISTORY_FILE
$ some_command
$ cat $MY_HISTORY_FILE
$ # ^You'll want to filter that down in practice!

IOバッファリングに問題がある可能性があります。また、ファイルが非常に大きくなる可能性があります。これらの問題の解決策を考え出す必要があります。


0

スクリプトコマンドを使用すると役立つと思います。何かのようなもの、

  1. スクリプト-c bash -qf fifo_pid

  2. 解析後にbash機能を使用して設定する。


0

前のコマンドを再計算したくない場合は、現在のターミナルバッファーをスキャンし、最後のコマンドの-supposed-出力を推測し、それをクリップボードにコピーして、最終的にターミナルに入力するマクロを作成できます。

1行の出力を返す単純なコマンドに使用できます(Ubuntu 18.04でテスト済みgnome-terminal)。

次のツールをインストールします。xdootoolxclipruby

gnome-terminal移動してPreferences -> Shortcuts -> Select all、に設定しCtrl+shift+aます。

次のルビスクリプトを作成します。

cat >${HOME}/parse.rb <<EOF
#!/usr/bin/ruby
stdin = STDIN.read
d = stdin.split(/\n/)
e = d.reverse
f = e.drop_while { |item| item == "" }
g = f.drop_while { |item| item.start_with? "${USER}@" }
h = g[0] 
print h
EOF

キーボード設定で、次のキーボードショートカットを追加します。

bash -c '/bin/sleep 0.3 ; xdotool key ctrl+shift+a ; xdotool key ctrl+shift+c ; ( (xclip -out | ${HOME}/parse.rb ) > /tmp/clipboard ) ; (cat /tmp/clipboard | xclip -sel clip ) ; xdotool key ctrl+shift+v '

上記のショートカット:

  • 現在の端末バッファをクリップボードにコピーします
  • 最後のコマンドの出力を抽出します(1行のみ)
  • 現在の端末に入力します
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.