タイムスタンプ付きのコマンド履歴を継続的に端末に出力するにはどうすればよいですか?


9

シンプルなエイリアスを使用して、1つまたは複数のターミナルウィンドウでコマンドの「追跡」を有効にします。

alias trackmi='export PROMPT_COMMAND="history -a; $PROMPT_COMMAND"'

次に、ワークスペースの別のターミナルにある.bash_historyファイルだけを使用しtail -fて、即座にフィードバックを得ます。無制限の履歴 を有効にし、.bashrcの履歴形式​​()を更新しました。もちろん、コマンドはタイムスタンプを表示します。しかし、履歴ファイル自体の形式は次のとおりです。export HISTTIMEFORMAT="[%F %T] "history

#1401234303
alias
#1401234486
cat ../.bashrc 

コマンドと同じように、Unix時間を変換してコマンド全体を1行に表示するにはどうすればよいですかhistory

578  [2014-05-27 19:45:03] alias
579  [2014-05-27 19:48:06] cat ../.bashrc 

...そしてそれに従ってください。または、historyコマンドの出力を端末に継続的に出力する方法を見つけますか?

回答:


7

GNUの場合awk

tail -fn+1 ~/.bash_history | awk '
  /^#/{printf "%-4d [%s] ", ++n, strftime("%F %T", substr($0, 2)); next}; 1'

他のソリューションを更新しfn+1て比較すると、最初は表示が速くなり、うまく機能します!ありがとう!

5

基本的にシェルのデフォルトからいくつかのコマンドで機能するまでの、分割画面xtermで動作する最終的な製品を次に示します。

ここに画像の説明を入力してください

スクリーンショットに示されているよりも大まかな方法​​は、次のようになります。

PS1='$( { date ; fc -l -0 ; } >${TGT_PTY} )'$PS1

どこに${TGT_PTY}あなたが出る何だろうtty、実際にあなたがあなたの出力をしたい画面上のインタラクティブシェルを実行しているときにコマンド。または、実際には、ファイルリダイレクトのターゲットにすぎないため、書き込み可能なファイルを使用することもできます。

私はそれが何らかのxtermであると想定しているので、疑似端末にpty構文を使用しますが、vtを専用にするのは簡単かもしれません-ストリーミングされた履歴は常に重要な組み合わせです。それが私なら、2つの概念を組み合わせて、専用のvtでセッションにすることもできますが、私は余談です。CTRL-ALT-Fnscreentmux

新しく起動したマシンでは/bin/login、典型的なLinux gettyコンソールの典型的なプロンプトが表示されます。私は押しCTRL-ALT-F2少なく、一般的なアクセスするためにkmscon、より多くのように振る舞うコンソールxtermよりをtty。コマンドを入力し、tty応答を受け取り/dev/pts/0ます。

一般的にxtermは、疑似端末を使用して単一の端末デバイスを複数に多重化します。そのため、X11で端末のタブまたはウィンドウを切り替えることで同様のことを行うと、同様に出力を受け取る可能性があります/dev/pts/[0-9]*。ただし、CTRL-ALT-Fnキーの組み合わせでアクセスされる仮想端末コンソールはtrue(er)端末デバイスであるため、独自の/dev/tty[0-9]*指定を受け取ります。

これが、コンソール2にログインした後tty、プロンプトで入力すると応答/dev/pts/0が表示されるのに、コンソール1で同じように入力すると、出力が表示されるため/dev/tty1です。いずれにせよ、コンソール2に戻って、次のようにします。

bash
PS1='$( { date ; fc -l -0 ; } >/dev/tty1 )'$PS1

認識できる影響はありません。さらにいくつかのコマンドを入力し続け、CTRL-ALT-F1もう一度押してコンソール1に切り替えます。そして<date_time>\n<hist#>\t<hist_cmd_string>、コンソール2で入力したすべてのコマンドのようなエントリが繰り返し見つかります。

ただし、端末デバイスに直接書き込むことを除いて、別のオプションは次のようになります。

TGT_PTY=
mkfifo ${TGT_PTY:=/tmp/shell.history.pipe}
{   echo 'OPENED ON:'
    date
} >${TGT_PTY}

そして多分...

less +F ${TGT_PTY}

大まかなプロンプトコマンドは仕様に適合していません。フォーマット文字列dateもフォーマットオプションfcもありませんが、そのメカニズムはそれほど必要ではありません。プロンプトが最後の履歴コマンドを表示するたびに、現在の日付と時刻が書き込まれます。${TGT_PTY}指定したファイル それはそれと同じくらい簡単です。

シェル履歴の監視と印刷は、fcの主な目的です。組み込まれてdateいない場合でも、組み込みのシェルです。中には、zsh fcタイムスタンプには適用されそのうちのいくつかは空想の書式設定オプションのすべての種類を提供することができます。もちろん、上記のように、bashさんhistoryも同じことができます。

よりクリーンな出力のために、ここで説明した手法を使用して、現在のシェルに永続的な追跡変数を設定できます。追跡してプロンプトシーケンス内のサブシェルで処理する必要があります。

仕様に合わせてフォーマットするポータブルな方法を次に示します。

_HIST() { [ -z ${_LH#$1} ] ||
    { date "+${1}%t[%F %T]"
      fc -nl -0 
    } >${TGT_PTY}
    printf "(_LH=$1)-$1"
}

: "${_LH=0}"
PS1='${_LH##*[$(($(_HIST \!)))-9]}'$PS1

最新の更新を追跡するだけのlast_historyカウンターを実装している$_LHため、同じ履歴コマンドを2回書き出さないでください。たとえば、Enterキーを押すだけです。現在のシェルで変数をインクリメントして、関数がサブシェルで呼び出されてもその値を保持するために、少しラングリングが必要です。これも、リンクで詳しく説明されています。

その出力は次のようになります <hist#>\t[%F %T]\t<hist_cmd>\n

しかし、それは完全に移植可能なバージョンです。でbash、それが少ないと、唯一のシェル組み込みコマンドを実装することによって行うことができます-あなたは、これはあなたが押すたびに実行するコマンドであることを考えると望ましい可能性があります[ENTER]。2つの方法は次のとおりです。

_HIST() { [ -z ${_LH#$1} ] || {
        printf "${1}\t[%(%F %T)T]"
        fc -nl -0
    } >${TGT_PTY}
    printf "(_LH=$1)-$1"
}
PROMPT_COMMAND=': ${_LH=0};'$PROMPT_COMMAND
PS1='${_LH##*[$(($(_HIST \!)))-9]}'$PS1

または、bashhistoryコマンドを使用して、次のように_HIST関数を定義できます。

_HIST() { [ -z ${_LH#$1} ] || 
        HISTTIMEFORMAT="[%F %T]<tab>" \
        history 1 >${TGT_PTY}
    printf "(_LH=$1)-$1"
}

どちらのメソッドの出力も次のようになります。<hist#>\t[%F %T]\t<hist_cmd>\nただし、historyメソッドにはいくつかの先行空白が含まれています。それでも、historyメソッドのタイムスタンプは、参照されたコマンドが完了するのを待ってからスタンプを取得する必要がないので、より正確になると思います。

あなたが何らかの形でストリームをフィルタリングする場合にのみ、両方のケースではまったくの状態を追跡避けることができるuniq-あなたがするかもしれないとmkfifo私は前に述べたように。

しかし、このようにプロンプ​​トでそれを行うことは、プロンプトを更新するという単なるアクションによって必要になったときにのみ、常に更新されることを意味します。それは簡単です。

あなたはまた、あなたがやっていることと同様のことをするかもしれませんtailが、むしろ設定されます

HISTFILE=${TGT_PTY}

別のタブで実際に編集しています...もっと時間をかけてください
mikeserv 2014年

...しかし、私はオフに左どこに表示されます-まあ、私は今、実際に、@照らす保存ヒットだろう
mikeserv

@illuminÉ-ちなみに-私はこれについて正しいと思います-コマンドを入力したとおりに入力した${TGT_PTY}と思いますか?もしそうなら、それは「あいまいなリダイレクト」を説明するでしょう。なぜならそれは空の変数だからです。ファイルが必要です。/dev/pts/[num]-すべての可能性で
mikeserv

うまくいきます!printscreenが役に立ちました!最初で唯一のコードブロックが印刷画面に入力したものであり、出力先の場所を選択し、関数にタブを入力するための明確な参照であることを願っています。他に何も必要ありません。変数を使用して手動で入力しなければならないことをすばやく説明するには、テキストを掘り下げてすべてを理解する必要があるため、解決策がわかりにくくなるので、私の考えではお勧めできません。また、あなたとあなたの家族にすべてのベスト。

@illuminÉ- cat私が偏執狂だったことを気にしないでください。12時間後でも問題なく動作します。
mikeserv 2014年

4

フォーマットして自由に遊んでもかまいませんが、これは(私は信じています)あなたが求めていることを行います... PATHのどこかに保存し、実行可能にして楽しんでください:

#!/bin/bash
count=$(  echo "scale=0 ; $(cat ~/.bash_history | wc -l ) / 2" | bc -l )
tail -f ~/.bash_history | awk -v c=$count '{if($1 ~/^#/){gsub(/#/, "", $1);printf "%s\t", c; "date \"+%F %T\" --date @" $1 | getline stamp; printf "[%s]\t",stamp;c++}else{print $0}}'

それは最適化できると確信していますが、あなたはそのアイデアを理解します。

簡単な説明:〜/ .bash_historyはカウントを追跡しないため、最初にエントリ数を決定します。次に、書式設定を正しく行うためのawkのちょっとした魔法を使い、エントリの数を追跡します。


複数行のエントリがある場合は機能しません。また、tail -fすでにに含まれている最初の10行を読み取りますcount。非POSIX環境でのGNU日付を想定しています(POSIXLY_CORRECTが設定されていません)。タイムスタンプごとに1つのシェルと1つの日付コマンドを実行します。
ステファンChazelas

@StephaneChazelas複数行のエントリの場合、私のセットアップでは、両方のソリューションに登録されているようです。多分私のセットアップで何か?

1
照らす@、ティンクのcount中に半分のライン数.bash_historyライン毎、その後、増分はないから始まる#報告履歴カウントが間違っていると思われるので、。使用count=$(grep -c '^#' ...)する方が良いでしょうが、いずれにしても、特に2つ以上のbashを同時に実行している場合は、これらの履歴番号が同期しなくなる可能性があります。
ステファンChazelas

@StephaneChazelas誠にありがとうございます。どちらの解決策も完全に理解することはできませんので、説明に感謝いたします。実際、カウントは異なり、結果的にここではるかに高くなります... strftimeを中心に独自のソリューションを構築したことがわかりますhistory。これは、基本的にコマンドが活用するものです。

1
フィードバック@StephaneChazelasをありがとう、私はそれらを回避できるかどうかを確認します:)
2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.