チュートリアル:履歴

Leonard Nimoyのドキュメンタリー音声をインポートして、xonshチュートリアルの準備をしてくださいhistory

xonshの歴史はどう違うのですか?

ほとんどのシェルは、歴史の中で端末に入力され過去のコマンドの線形シーケンスと考えていますこれは シェルが終了するときに保存され新しいシェルが起動するとき読み込まれます。しかし、これはもはや世界の仕組みではありません。

世界は乱雑で非同期的な場所です。私たちは通常、一度に少なくとも多くの端末(およびシェル)をオープンしています。xonshでは、歴史はこれが事実であることを認めます。単一の履歴ファイルの入力ではなく、xonshはJSON形式の履歴ファイルのコレクションを実装しています。このファイルは、次の構造を持つと考えることができます。

{'env': {...},  # Environment that xonsh was started with
 'sessionid': str, # UUID4 for the session
 'ts': [start, stop],  # start and stop timestamps for session [s since epoch]
 'locked': True,  # boolean for whether the file is in use or not
 'cmds': [  # array of commands
    {'inp': str,  # input command
     'ts': [start, stop],  # timestamps for the command
     'rtn': int, # command return code
     'out' str,  # stdout and stderr of command, for subproc commands
                 # this is only available on Linux. Off by default.
     },
    ...
    ],
}

この豊富なデータセットにより、Xonshはより高度な検査と操作を行うことができます。セッションID、ロック、およびシェルごとの1ファイルのアイデアにより、複数のxonshインスタンスが同時に競合することなく、同時に上書きされることなく、同時に実行できます。もちろん、履歴ファイルを削除する外部プロセスは依然として問題を引き起こす可能性があります。しかし、ちょっと、世界とファイルシステムは厄介な場所です!

なぜ豊かな歴史がありますか?

歴史的なアーティファクトが必要であることが分かっている時には、それはすでに遅すぎます。あなたは覚えていない:

  • 入力は正確に、
  • あなたはあなたが出力を覚えていると思いますが、コマンドを再実行するときに今何が得られるかは何とか違って見えますが、
  • 戻りコードが何であるかを知っている人は、
  • あなたが直前に実行したコマンドは、時間の霧の中で今失われています!

豊かな歴史を持つ理由は、デバッグと再現性です。Xonshは推測作業を過去から取り除いています。stdoutをすべて格納する機能さえありますが、これはデフォルトではオフになっています。履歴が単なる静的ファイルの場合は、伝統的な履歴ファイルよりもサーバーログに似ています。ただし、xonshにreplayは履歴ファイルの機能もあります。

履歴を再生すると、以前のセッションが新しい環境または同じ環境のスクリプトとして機能します。再生すると、別個の新しい履歴セッションとファイルが作成されます。2つの履歴は、たとえそれらが同じ入力を含んでいても異なっている可能性があります。diffは、xonshカスタム履歴差分ツールを使用して実行することができます。このツールを使用すると、環境や入出力から生じる差異を特定するのに役立ちます。do-replay-diffのこのサイクルは、伝統的な「宇宙はどうしたのですか?」アプローチよりも意味があります。

もちろん、何も今までのようなUnixツールを引っ張ってから誰にも止めなかったenvscriptdiff機能の同じ種類を提供するために、そして他の人一緒に。しかし、実際には、誰もこれを行いません。xonshで、豊かで有用な歴史は電池を含んで来る。

historyコマンド

すべてのxonsh履歴の検査と操作は、トップレベルのhistory エイリアスまたはコマンドを実行します。action引数なしでこれを実行すると、デフォルトでshowアクションが実行されます(以下を参照)。

>>> history

また、xonsh組み込み変数を使用して、履歴オブジェクト自体にアクセスできることにも注意してください __xonsh__.history

showアクション

showhistoryコマンドアクションhistoryは、他のシェルでコマンドが実行する動作を模倣しています。つまり、これらの入力のインデックスとともに過去の入力を表示します。これはデフォルトで現在のセッションで動作し、historyコマンドのデフォルトの動作です例えば、

>>> 1 + 1
2
>>> history show
 0  1 + 1
>>> history
 0  1 + 1
 1  history show

注意

履歴はゼロインデックスされています。これはまだPythonです。

また、任意の整数(履歴インデックスを表示するだけの場合)またはスライス(履歴インデックスの範囲を表示する場合)を引数として取ることもできます。上から偶数のインデックスだけを表示するには、次のように書くことができます。

>>> history show ::2
 0  1 + 1
 2  history

多くのスライス/整数引数を使用して、履歴の異なる部分を取得することもできます

show返される履歴を示すオプションのに使用することができます:

xonshで見つかったすべての有効なjsonファイルからの過去の入力を表示しますXONSH_DATA_DIRしたがって、これはすべての過去および現在のxonshセッションで動作します。

allの別名ですxonsh

zshHISTFILEzshの環境変数で指定された履歴ファイルのすべての履歴を表示しますデフォルトではこれは~/.zsh_historyです。しかし、彼らはまた、それぞれの両方で指定することができる~/.zshrc~/.zprofileXonshはこれらのファイル(最初にrcファイル)を解析しHISTFILEて、設定されているかどうかをチェックします

bashアクションはで指定された履歴ファイルからすべての履歴を表示しますHISTFILEbashで環境変数。デフォルトではこれは~/.bash_historyです。しかし、彼らはまた、それぞれの両方で指定することができる~/.bashrc~/.bash_profileXonshはこれらのファイル(最初にrcファイル)を解析しHISTFILEて、設定されているかどうかをチェックします

show履歴出力をより詳細に制御するための他のオプションも-n使用できます。オプションはコマンドを列挙するために使用され、-tオプションはタイムスタンプを表示するために使用され、さらにオプションのリストを試します。history show --help

idアクション

各xonshの歴史には独自のユニークさがありsessionidます。idアクションは、これが識別表示方法です。例えば、

>>> history id
ace97177-f8dd-4a8d-8a91-a98ffd0b3d17

fileアクション

同様に、各xonshヒストリには、関連する独自のファイルがあります。fileアクションは、このファイルへのパスを表示する方法です。例えば、

>>> history file
/home/me/.local/share/xonsh/xonsh-ace97177-f8dd-4a8d-8a91-a98ffd0b3d17.json

これらのファイルは$XONSH_DATA_DIR環境変数に格納されることに注意してくださいこれは、デフォルトでxonshは、無料のデスクトップ標準$XDG_DATA_HOME環境変数の内部に 設定されています。詳細は このページ参照してください。

infoアクション

infoアクションは、idアクションを組み合わせfile、履歴の現在の状態に関する追加情報を追加します。デフォルトでは、キーと値の一連の行が出力されます。ただし、JSON形式の文字列も返すことができます。

>>> history info
sessionid: ace97177-f8dd-4a8d-8a91-a98ffd0b3d17
filename: /home/scopatz/.local/share/xonsh/xonsh-ace97177-f8dd-4a8d-8a91-a98ffd0b3d17.json
length: 6
buffersize: 100
bufferlength: 6
>>> history info --json
{"sessionid": "ace97177-f8dd-4a8d-8a91-a98ffd0b3d17",
 "filename": "/home/scopatz/.local/share/xonsh/xonsh-ace97177-f8dd-4a8d-8a91-a98ffd0b3d17.json",
 "length": 7, "buffersize": 100, "bufferlength": 7}

replayアクション

このreplayアクションによって、履歴ファイルをスクリプトとして、または既存のxonshセッションで再実行することができます。

最初に、元の'replay'環境がロードされ、現在の'native' 環境とマージされます。再生時に、環境のマージ方法やマージされない方法を設定できます。デフォルトでは、現在のネイティブ環境が優先されます。次に、環境内の各入力が順番に実行されます。最後に、再生された履歴ファイルの情報が印刷される。

例を見てみましょう。まず、xonshを開き、次のような簡単なコマンドを実行します。これをorigセッションと呼んでください

起源の歴史

>>> mkdir -p temp/
>>> cd temp
>>> import random
>>> touch @(random.randint(0, 18))
>>> ls
2
>>> history file
/home/scopatz/.local/share/xonsh/xonsh-4bc4ecd6-3eba-4f3a-b396-a229ba2b4810.json
>>> exit

ファイル名をreplayコマンドまたはhistoryコマンドの再生アクションに渡すことでこれを再生できるようになりました。このアクションにはいくつかのオプションがありますが、その1つは-oor --targetオプションを使用して別のターゲット出力ファイルを選択できることです。たとえば、新しいセッションでは次のように実行できます。

新しい歴史

>>> history replay -o ~/new.json ~/.local/share/xonsh/xonsh-4bc4ecd6-3eba-4f3a-b396-a229ba2b4810.json
2  10
/home/scopatz/new.json

----------------------------------------------------------------
Just replayed history, new history the has following information
----------------------------------------------------------------
sessionid: 35712b6f-4b15-4ef9-8ce3-b4c781601bc2
filename: /home/scopatz/new.json
length: 7
buffersize: 100
bufferlength: 0

ご覧のように、新しい履歴が作成され、別のランダムなファイルがファイルシステムに追加されました。独自のセッションで履歴を再生する-c場合は、xonsh自体でオプションを使用して、replayコマンドを実行することができます。

次の歴史

>>> xonsh -c "replay -o ~/next.json ~/new.json"
2  7  10
/home/scopatz/next.json

----------------------------------------------------------------
Just replayed history, new history has the following information
----------------------------------------------------------------
sessionid: 70d7186e-3eb9-4b1c-8f82-45bb8a1b7967
filename: /home/scopatz/next.json
length: 7
buffersize: 100
bufferlength: 0

現在のところ、履歴はエイリアスの保存と再読み込みは処理されませんが、このような機能は今後登場する可能性があります。

diffアクション

任意の2つの履歴ファイルの間で、diffアクションを実行できますこれは、unix diffコマンドを使って生成する単純な行diffよりも多くのことを行います(もしあなたがline diffを使いたいのであれば、unixコマンドを使ってください!)代わりに、環境、入力、出力(利用可能な場合)、そして戻り値に関してもっと洗練された差分を行うxonsh履歴ファイルがあることを知っているという事実を利用します値。もちろん、diffが有意義であれば、履歴入力は「十分に似ている」必要があります。しかし、それらはまったく同じである必要はありません。

diff操作は、一つの大きな選択肢を持っている、-vまたは--verboseこれは、基本的に、diffができるだけ詳細になるか、関連する部分だけを選ぶかを指定します。リプレイアクションから新しいサンプルと次のサンプルを区別すると、diffは次のようになります。

>>> history diff ~/new.json ~/next.json
--- /home/scopatz/new.json (35712b6f-4b15-4ef9-8ce3-b4c781601bc2) [unlocked]
started: 2015-08-27 15:13:44.873869 stopped: 2015-08-27 15:13:44.918903 runtime: 0:00:00.045034
+++ /home/scopatz/next.json (70d7186e-3eb9-4b1c-8f82-45bb8a1b7967) [unlocked]
started: 2015-08-27 15:15:09.423932 stopped: 2015-08-27 15:15:09.619098 runtime: 0:00:00.195166

Environment
-----------
'PATH' is in both, but differs
- /home/scopatz/.local/bin:/home/scopatz/sandbox/bin:/home/scopatz/miniconda3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/scopatz/origen22/code/
+ /home/scopatz/.local/bin:/home/scopatz/sandbox/bin:/home/scopatz/miniconda3/bin:/home/scopatz/.local/bin:/home/scopatz/sandbox/bin:/home/scopatz/miniconda3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/scopatz/origen22/code/:/home/scopatz/origen22/code/

'SHLVL' is in both, but differs
- 2
+ 3

'XONSH_INTERACTIVE' is in both, but differs
- True
+ False

These vars are only in 70d7186e-3eb9-4b1c-8f82-45bb8a1b7967: {'OLDPWD'}

Commands
--------
cmd #4 in 35712b6f-4b15-4ef9-8ce3-b4c781601bc2 input is the same as
cmd #4 in 70d7186e-3eb9-4b1c-8f82-45bb8a1b7967, but output differs:
Outputs differ
- 2  10
+ 2  7  10

cmd #5 in 35712b6f-4b15-4ef9-8ce3-b4c781601bc2 input is the same as
cmd #5 in 70d7186e-3eb9-4b1c-8f82-45bb8a1b7967, but output differs:
Outputs differ
- /home/scopatz/new.json
+ /home/scopatz/next.json

ご覧のように、diffには3つのセクションがあります。

  1. ヘッダーには、ファイル名、セッションID、タイムスタンプなど、履歴に関するメタ情報が記述されています。
  2. 環境セクションでは、履歴が開始または再生されたときの環境の違いについて説明します。
  3. これらのコマンドは、コマンド自体にこの違いをリストします。

コマンドの場合、出力シーケンスが比較される前に入力シーケンスが先にdiffされます。端末では、これは色で表示され、最初の履歴は赤色で、2番目の履歴は緑色で表示されます。

gcアクション

最後の、しかし確かではないが、gcアクションは履歴のガベージ・コントロールを実行するための手動フックです。歴史は多くの情報を格納する可能性があるため、しばらく毎回キャッシュを掃除できるようにする必要があります。

ガーベージ・コントロールは、xonshスレッドごとに自動的に起動されますが、バックグラウンド・スレッドで実行されます。ガベージコレクタは、ロックされていない履歴ファイルに対してのみ動作します。ここでのアクションは、おそらく異なる基準で、新しいガベージコレクタを手動で開始することを可能にします。

通常、ガベージコレクタは環境変数$XONSH_HISTORY_SIZE使用して、ディスク上に残すべきもののサイズと単位を決定します。デフォルトでは、これはです。この変数は通常、ここに示すようにタプルまたは数字と文字列のリストです。ただし、同じ情報を持つ文字列を使用することもできますしかし、コマンドラインでは、オプションに2つの引数を渡すだけです。(8128, 'commands')'8128 commands'--size--size 8128 commands

ガベージコレクタは、4つの正準ユニットを受け入れます。

  1. 'commands' は、過去に実行されたコマンドの数を制限するためのものです。
    履歴ファイル、
  2. 'files' 保持する履歴ファイルの総数を指定するためのもので、
  3. 's' 過去に許容されている秒数です。これは事実上履歴ファイルのタイムアウトになります。
  4. 'b' すべてのヒストリー・ファイルがまとめて消費するためにファイル・システム上で許可されるバイト数です。

しかし、他のユニット、別名、適切な変換関数が実装されています。これにより、人にやさしい値に基づいてガーベッジ・コレクションを簡単に行うことができます。

GCエイリアス:

{'commands': ['', 'c', 'cmd', 'cmds', 'command'],
 'files': ['f'],
 's': ['sec', 'second', 'seconds', 'm', 'min', 'mins', 'h', 'hr', 'hour', 'hours',
       'd', 'day', 'days', 'mon', 'month', 'months', 'y', 'yr', 'yrs', 'year', 'years'],
 'b': ['byte', 'bytes', 'kb', 'kilobyte', 'kilobytes', 'mb', 'meg', 'megs', 'megabyte',
       'megabytes', 'gb', 'gig', 'gigs', 'gigabyte', 'gigabytes', 'tb', 'terabyte',
       'terabytes']
 }

すべてのことを言って、1か月以上経過したすべての履歴ファイルを削除する場合は、次のコマンドを実行します。

>>> history gc --size 1 month

履歴インデックス作成

ヒストリオブジェクト(__xonsh__.history)は、特殊な機能を追加する特殊な方法でインデックスを付けることができるシーケンスのように機能します。現時点では、現在のセッションの履歴のみを取得できます。最新のコマンドは履歴の最後の項目であることに注意してください。

インデックスは、コマンドと引数の2つの部分がカンマで区切られたフィルタとして機能します。異なるフィルタリングの各部分のタイプに基づいて達成することができ、

コマンド部の場合:
  • intはその位置でコマンドを返します。
  • スライスはコマンドのリストを返します。
  • 文字列は、その文字列を含む最新のコマンドを返します。
引数部分について:
  • intはその位置のコマンドの引数を返します。
  • スライスは引数の位置に基づいてコマンドの一部を返します。

フィルタの引数部分は省略できますが、コマンド部分は必須です。

コマンド引数は空白で区切られています。

フィルタリングで生成される結果が1つだけの場合は、文字列として返されます。そうでない場合は、文字列のリストが返されます。

例:

>>> echo mkdir with/a/huge/name/
mkdir with/a/huge/name
>>> __xonsh__.history[-1, -1]
'with/a/huge/name/'
>>> __xonsh__.history['mkdir']
'echo mkdir with/a/huge/name'
>>> __xonsh__.history[0, 1:]
'mkdir with/a/huge/name'

興味深い技術的詳細:Lazy JSON¶

だから、あなたは履歴を調べ、実行し、そして削除する方法を知っている。しかし、何履歴ファイルは正確に?xonshの履歴ファイルはJSON形式であり、ページの上部に示された構造を持っていますが、これはトップレベルの構造ではありません。あなたが1つを開くと、あなたは何かに現実に出くわす前に、たくさんのホックを見ます。

Xonshは、索引付けするファイルの内部に存在するJSONファイルの汎用索引システム(サイズ、オフセットなど)を実装しています。これはLazyJSON、私たちが必要とするファイルの部分だけを読み込むことができるためです。たとえば、再生のために入力フィールドを取得するだけでI / Oに役立ちます。コマンドの数に基づくガベージコレクションの場合、この情報をインデックスから取得することができ、元のデータを読み込む必要はありません。

これに関する最良の部分は、それが完全に一般的であるということです。xonsh.lazyjson xonshの歴史以外のものにあなた自身を使用することを自由に感じてください!もちろん、xonshの履歴を読みたい場合は、おそらくモジュールを使うべきです。

エキサイティングな技術的な詳細:ティーと疑似ターミナル

Xonshは、すべてのstdoutとstderrを透過的かつ応答的にキャプチャすることができます。エイリアス、Pythonコード、またはxonshコードの場合、これは大きな問題ではありません。情報が流れるリダイレクトすることは容易であるsys.stdoutsys.stderrサブプロセスコマンドの場合、これはかなり困難です。stdoutの保存はデフォルトでは無効になっていますが$XONSH_STORE_STDOUT=True~/.xonshrcファイル内で設定することで有効にすることができ ます。

stdoutとstderrをteeできるようにするために、xonshはPython標準ライブラリptyモジュールの上に独自のteeing疑似端末を実装しています。このクラスはxonsh.teeptyモジュールで見つけることができます。遅いJSONと同様に、これはxonshの他の部分とは独立しており、単独で使うことができます。これが他の分野で役立つと思われる場合は、お知らせください。

Sqlite履歴のバックエンド

Xonshには、sqliteによって強化された2番目の組み込み履歴バックエンドがあります(このチュートリアルの上で説明したJSONバージョン以外)。それが現在サポートされていない以外は、ほとんどの方法でJSONのバージョンと同じ機能を共有し、行動。history diffhistory replay

Sqlite履歴バックエンドは、ちょうど開始されたxonshセッションに履歴を読み込む際のスピード上の利点を提供します。JSON履歴のバックエンドは、何千ものjsonファイルを読み込む必要があり、sqliteバックエンドは1つだけを読み込みます。これは起動時間には影響しませんが、すべての履歴が検索可能になるまでの時間に注意してください。

sqlite履歴バックエンドを使用するには、ファイルに設定しますJSONバージョンに戻すには、この行を削除するか、またはに設定します。$XONSH_HISTORY_BACKEND = 'sqlite'~/.xonshrc'json'

注意

SQLite履歴のバックエンドは現在、ガベージコレクションのcommandsユニットとしてのみサポートされてい$XONSH_HISTORY_SIZEます。

先端

あなたが持っている場合はsqliteのウェブが インストールされ、次のコマンドで簡単に歴史を読むことができます: sqlite_web @$(history file)

履歴データのための楽しいアイデア

今、私たちはこの歴史のデータをすべて持っているので、私たちがここに持っているものはちょうど氷山の先端です!私が思うにうまくいけば楽しいアイデアがあります。

  • コマンドの使用法、タイミングなどに関する基本的な統計レポート、
  • 多くの人々から匿名化された履歴を収集し、
  • 入力用のMCMCベースのタブコンプリータ、
  • などなど!

xonshの内部または外部のいずれかで作業することに興味があるかどうかをお知らせください。