はじめに
もしかすると誰もが通る道なのかもしれないが、history
コマンドを使いこなせたら作業早くなるかもなぁ、と思って調べた内容。(コマンド全て覚えるのはめんどうというのもある)
myPCがfish
だったばかりに、bash
とは違う情報がいろいろ出てきて面白かったので、まとめてみました。
これを読めば、
-
fish
のhistory
の使い方について -
fish
のhistory
を使うときに調べるであろうことについて
知ることができると思います。
随所に、悪い癖で自分の思ったことをつらつらつらと書いた箇所があるので私がなぜにfishだったのか?・「ユーザーフレンドリ」なものに悪いものはいない?など、時間ない人は読み飛ばしちゃってください。
私がなぜにfish
だったのか
もちろん、myPCにfish
を入れた犯人は私です。
一番の理由は、新入社員だった頃に、若手の先輩に激推しされたことでした。
聞くところによると、「ユーザーフレンドリ」なシェルらしいということで、「ユーザーフレンドリ」なものに悪いものはないだろうと入れました。
今回、fish
のhistory
を調べたことで、fish
の概念のようなものも、ちょっとは知ることができた気がするので、そこいらへんも少し書きたいと思います。
bash
のhistory
との違い
書式とオプション(サブコマンド)の違い
一番大きな違いは、「サブコマンド
という概念」と、「コマンドのオプションの内容」かと思います。
まずは、比較のためbash
のhistory
の書式と主なオプションについておさらいしてみましょう。
bashの場合
history [オプション]
history オプション [ファイル]
オプション | 意味 |
---|---|
整数値 | 履歴の末尾から指定した行数分を表示 |
-c | 履歴一覧から全ての項目を削除 |
-d 番号 | 指定した番号の履歴項目を削除 |
-a | 履歴ファイルに現在のセッションの履歴を追加 |
-n | 履歴ファイルから読み込まれていない行を全読み込み |
-r ファイル | 履歴ファイルを読み込み、内容を履歴一覧に追加 |
-w ファイル | 現在の履歴を履歴ファイルに上書き |
次はfish
のhistory
についてですが、サブコマンド
の影響で、bash
のhistory
よりも書式が多彩になっています。
fishの場合
# 検索文字列にマッチする履歴を出力
history search [オプション] [ 'search string'... ]
# 指定された文字列に該当する履歴のエントリを削除
history delete [オプション] 'search string'...
# 他のfishセッションからの履歴の更新をマージ
history merge
# すべての更新を履歴ファイルに書き込み(自動的に保存されるのでほぼ使用しない)
history save
# 履歴ファイルをクリア
history clear
# 全履歴を出力(結果的には history = history search となる)
history
サブコマンド
とはhistory
に続く、
search
、delete
、merge
、save
、clear
の部分です。
それぞれ上記で示した用途で利用されます。
オプション | 意味 | 対応しているサブコマンド |
---|---|---|
-C / --case-sensitive | 大文字小文字を区別 |
search /delete
|
-c / --contains | 指定された文字列に部分一致 |
search /delete |
-e / --exact | 指定された文字列に完全一致 |
search /delete |
-p / --prefix | 指定された文字列に前方一致 |
search /delete |
-t / --show-time |
history 項目の日時表示 |
search /delete |
-z / --null | 改行の代わりにヌル文字を表示の区切りとして使用 | search |
-<number> / -n <number>
|
<number> にマッチした数だけhistory 項目を表示 |
search |
-R / --reverse | 新しい順から古い順に変更 | search |
補足
-<number>
/ -n <number>
は他に--max=<number>
という書き方もあります。
history = history search
のため、search
で利用できるオプションはhistory
でも利用できます。
何もかも違うと言って過言じゃないですが、
何となく違いを捉えるなら**「fishの方がhistoryの検索に長(た)けている」**という理解で大丈夫だと思います。
少し自分なりの書き方をしている部分もありますので、正確な情報は以下を参照してください。
公式サイトのhistoryのページ
全訳!fishシェル普及計画のhistoryのページ
使い方の違い
サブコマンドsearch
、delete
の使い方について一例を示してみます。
例) which
コマンドでパスの確認を行った履歴を日時とともに表示する。
history search -t which
# 出力
# 金 8/ 9 20:41:17 2019
which pyenv
# 金 8/ 9 20:40:39 2019
which node
# 金 8/ 9 20:40:11 2019
history which
# 水 5/29 00:17:15 2019
which fish
# 水 5/15 21:16:26 2019
which python
# 水 5/15 20:38:13 2019
which bash
なんだったら、(さっきからしつこく書いてますが)history = history search
だと使っていたら分かるので、search
も書かなくていいです。history
はデフォルトでgrep
の機能もくっついてるようなものだと思ってもらったらいいと思います。
例)which
コマンドの履歴の一部を削除する
history delete -p which
#出力
[1] which pyenv
[2] which node
[3] which fish
[4] which python
[5] which bash
Enter nothing to cancel the delete, or
Enter one or more of the entry IDs separated by a space, or
Enter "all" to delete all the matching entries.
Delete which entries? >
delete
のサブコマンドを使うと、上記のような出力結果が得られます。
検索した全ての履歴を削除したい場合はall
をタイプしてEnterしたらいいし、which node
とwhich fish
を削除したいなら、2 3
とタイプしてEnterしたらOKです。
delete
を使って複数の検索結果を得たい場合は、基本的に部分一致の-c / --contains
か前方一致の-p / --prefix
のオプションをつけます。
(余談)
公式ドキュメントを読む限りは、delete
のデフォルトのオプションは-e / --exact
ですが、挙動および公開されているソースを確認すると-c / --contains
になっています。ドキュメントとソースどちらが間違っているか、今のところはっきりとしていません。
表示の挙動の違い
bash
と比べて以下のような表示の違いがあります。
-
history
の項目が、新しい順で表示される。 - (コマンドラインの)1画面ずつ
history
の項目が表示される。(デフォルトでhistory | more
を実行したようなイメージ)
確かに、古い順で全部表示されるより、新しい順で画面に出力できる範囲で表示された方が便利ですよね。(流石「ユーザフレンドリ」)
bash
でよくやる設定について
さてさて、fish
とbash
のhistory
の違いはよく分かった、お腹いっぱいとなった私。
今度はfish
のhistory
を使いこなしたい(便利に使いたい)!と思い立つことになります。
そして私は気づくのです。「bash
だとhistory
を便利にするために、いろいろと設定するよな?」ということに。
つまり、bash
で設定することをfish
だったらどうやって設定するんだろうと思ったわけです。
以下、いろいろと調べましたが、設定できなかったものもありますのでご注意ください。
コマンド履歴の保存件数を増やす
デフォルトの500個は少なすぎる!ってことでbash
だと一番最初に設定するのではないでしょうか。お馴染みHISTSIZE
に値を設定する作業。
fish
はどうやって設定するのか?
答えは、なんと設定できないという落ちになります。
実は、fishにHISTSIZEなんてものはない
デフォルトで256k個保存できるから大丈夫っしょ?って感じ↓
https://github.com/fish-shell/fish-shell/issues/2674
そうなのか・・・。まあ256k個もあるならいいか・・・
historyに日時を付与する
bash
のノリでいくと、HISTTIMEFORMAT
に日時の出力形式を設定する、という話になるわけだが、HISTTIMEFORMATに類するものはfishには(これまた)存在しない。
オプションの-t / --show-time
を使いましょう、ということらしい。
オプションつけるのも面倒くさい!!という人にはalias
で設定するという方法があるかと思います。
historyに日時を付与するaliasの設定方法(あくまで一例)
alias thistory "history --show-time='%Y-%m-%d %H:%M:%S '"
funcsave thistory
表示形式の変更する場合は、基本的には-t
の短縮形ではなく--show-time
を使います。
上記で定義したthistory
の実行結果は以下の通りです。
thistory -p which
# 出力
2019-08-09 20:41:17 which pyenv
2019-08-09 20:40:39 which node
2019-05-29 00:17:15 which fish
2019-05-15 21:16:26 which python
2019-05-15 20:38:13 which bash
ちなみにデフォルの表示形式だと使い方の違いで示したように、改行が入ります。
(上記の表示形式の方が慣れている人が多いかもしれません)
〜横道〜 aliasの話
historyに日時を付与するで示した通り、fish
におけるalias
は設定ファイルに記述するのではなく、コマンドラインで設定(alias)して保存(funcsave)することができます。
「ユーザフレンドリ」としてはかなりの美点なのではないでしょうか。
が、しかし、、**元々存在する関数と同名の別名は定義できません。**とのこと。
やってみると、できてしまうのですが(苦笑)
挙動がおかしくて、戻し方を知らないと混乱するのでやらないのが無難です。
ちなみにfish
のalias
は中身的にはfunction
コマンドになります。
参考
aliasのドキュメント(公式を元にした日本語翻訳版)
functionのドキュメント(公式を元にした日本語翻訳版)
また、abbr
コマンドというものもあります。(どちらかというと、こちらの方が他のシェルのalias
、別名定義に近いようです)↓
短縮形を管理するコマンドではありますが、abbr
だと同名での定義もできます。
abbr
とalias
(function
)の違いも、色々と試してみましたが、奥が深そうでした・・・。今回は内容書き出すと趣旨とどんどんずれていくので割愛します。
特定のコマンドの履歴を保存しない
ls
やhistory
コマンド自体など、別段history
に残しておかなくていいコマンドを保存しておきたくない!!ってときの話。
まず前提ですがfish
には以下のような特徴があります。
- そもそも重複するコマンドの履歴は保存されない。
- 先頭に空白を記述すると、履歴に保存されない
上記がデフォルトの挙動です。
history -e ll
とかしても結果は一つしか出てこないし、ll
コマンドを実行する度に記録される時間は更新される、、といった具合です。
bash
でいう、
HISTCONTROL=ignoreboth
のような状態です。
さてさて、「特定のコマンドの履歴を保存しない」設定ですが、当然のようにfish
にはHISTCONTROL
やHISTIGNORE
に類するものはありません・・・。
先人の知恵としては以下のようなものがあります。
(1) https://github.com/fish-shell/fish-shell/issues/2788
issueの回答として以下のようなfunction
が記載されています。
function ignorehistory --on-event fish_prompt # or maybe fish_preexec, see function --help
history --delete fg bg
end
簡単な説明ですが、
上記のfunction
の意味は「fish_prompt
が実施される度にhistory
の中のfg
とbg
のコマンドの履歴を削除する」ってな具合。
fish_prompt
については(超入門)fishでプロンプトを変えたい人へのチュートリアルを参照ください。
「fish_prompt
が実施される度」というのは、つまりは「コマンドラインを起動した・コマンドを実行する度」ということになります。
使い方の違いで示しましたが、サブコマンドdelete
は複数の削除候補が出てくると、全て削除するか一部を削除するか聞いてくるので、上記のfunction
は場合によっては鬱陶しいんじゃないかなぁと個人的には思っています。(この挙動は上記function
にオプション--exact
を付与すると改善されるかもしれません)
〜横道〜 aliasの話で少し触れたabbr
コマンドを使って、保存しておきたくないコマンドの先頭に空白を付与して別名保存します。
abbr -a history ' history'
先頭に空白を記述すると、履歴に保存されないというfish
の挙動を利用した形です。
設定するならこちらの方がいいのではないかと思います。
参考サイト(2)の最後に書かれている関数については(1)と同じ理由で、個人的には非推奨です。
ちなみに
逆に、重複するコマンドの履歴も保存できるようにする術はなさそうです。
個人的には、重複するとは言え、「いつごろ、このコマンド使ったっけ?」というのを調べることもあるんじゃないかなぁ、、と思うのですが、調べた限りは見つかりませんでした。
history expansion について
設定とは少し違いますが、、history expansion
について、
history expansion
とはbash
などで![行番号]
と指定すると、history
の行番号に該当するコマンドが実行される、あの機能のことです。(!!
打つと、直前のコマンドが実行されたり、、詳しくは→https://mseeeen.msen.jp/bash-history-expansion/)
fish
には![行番号]
の記述方法は・・・ない!(そもそもhistoryに行数ついてない・・・)
これは公式のFAQでも、言及されています。(すごくfish
側のこだわりを感じるところだと、勝手に思っています)
Why doesn't history substitution ("!$" etc.) work?
(日本語版)履歴置換(!$など)はなぜ動かないの?
「ないんだけど、fish
は対話的に履歴を探し出すことに秀でているから、そっちの機能を使ってね!」っという感じ。
fish
を愛用されている方にはお馴染みなのかもしれないが、
例えば、コマンドの一部を入力して上矢印を押すと、記述したコマンドに限定して履歴を遡れたりします。(cd
コマンド等で試してもらうと、極めて強力だということが分かるのではないでしょうか)使い慣れると![行番号]
よりもはるかに便利だと、私は思っています。
どーーーしても!
を使いたい場合は、sudo !!
に対してfunction
で設定する方法がissueに紹介されています。(sudo
つけ忘れたコマンドにsudo
をつける用途)
https://github.com/fish-shell/fish-shell/issues/288
function sudo
if test "$argv" = !!
eval command sudo $history[1]
else
command sudo $argv
end
end
ちなみに、公式のFAQには上矢印一回して、homeボタン押してからsudo
書けばいいじゃないか!、と書いてあります。
「ユーザーフレンドリ」なものに悪いものはいない?
先ほどから度々参照している、全訳!fishシェル普及計画のサイトに設計理念というメニューがあり、設計原則の一つにこんなことが書かれています。
「設定可能性」は諸悪の根源
プログラム内のすべての設定オプションはユーザが本当に求めているものを理解するにはあまりにも馬鹿げている場所です。 また、設定オプションはプログラムとそれを実装したプログラマの双方の障害を考慮すべきです。
「根拠」ではさまざまな設定オプションをメンテナンスするのは悪夢のように困難です。
と続きます。
私が何を言いたいのかというと、上記で長々と書いたbashでよくやる設定についての内容は、
真っ向からこの原則に反発した形であり、
本当にfish
で設定する必要があるのか否か、一考する余地がある、、ということです。
以下にbashでよくやる設定についてで調べた内容について、個人的に思う「設定しなくていい理由」を書いてみました。
○ コマンド履歴の保存件数を増やす
(設定する方法すらありませんが・・)デフォルトで256k個もの件数が保存でき、また「重複するコマンドの履歴は保存されない」デフォルトの挙動で保存される履歴も限られている中で、これ以上件数を増やす設定は必要でしょうか?
○ historyに日時を付与する
元々、-t / --show-time
のオプションで、日時の表示・非表示が自在に変更できる状況で、alias
に設定する必要はどこまであるでしょうか?
○ 特定のコマンドの履歴を保存しない
無理に設定しなくてもサブコマンドのdelete
を使えば、必要のない履歴はすぐ消すことができます。また、よく必要ないと目される決まったコマンドは「重複するコマンドの履歴は保存されない」の影響で、1つしか登録されない場合が多いはずです。(一つでも登録されるのが気持ち悪いという場合は必要かもしれません)
○ history expansion について
慣れたらfish
の補完の方が便利だと思います。設定してしまうと、fish
の良さを蔑ろにしてしまう節があります。
原則を鑑みると、そもそも、(私自身そうでしたが)**使いやすくするために、設定ファイルを編集しないといけない!!**という発想自体がfish
においては間違っていると言えそうです。
少なくともbash
で設定していたからとfish
でも設定すべきかどうかは、甚だ疑問です。(耳が痛い・・・)
「ユーザフレンドリ」なfish
は、**ガチガチに自分好みに使いたい!!**という人には、もしかすると悪
にもなり得るのかもしれません。
fish
は「いいぞ」ユーザフレンドリは「いいぞ」という記事が多いですが、history
の使い方を通して、場合によっては不便な一面もあるのかなぁ、という参考資料になってくれたら幸いに思います。(fish
に乗り換えようかと検討されている方の一助になれば・・・)
何かしら設定する方法
語弊がありそうなので蛇足を書きますが、もちろん、何も設定してはいけない、というわけではないと思います。
「他のシェルほど自分好みに設定できないところがあるけど、我慢してね。一応デフォルトで使いやすくしているつもりだよ」
くらいだと思います。
何か設定するときは、
fish shellが結構良かった話でも紹介されている。
fish_config
を使うと、ブラウザでグラフィカルに設定をいじることができます。
最後に
サブコマンドのsearch
やdelete
は便利なので、知らなかった人は覚えておいて損はないと思います。
また、fish
で何かしら「設定しよう」と思ったときは、まずはfish
がデフォルトでどんな挙動をしているのか調べるのがおすすめです。(調べてみると、今回のようにそれなりに考えられた挙動だったりします)
fish
について批判的な文も書きましたが、最終的には**とても使いやすい!!**と思っています。(特に補完機能)
なんだかんだ、これからも使っていく所存です!!
参考
fish
について
公式サイト
→ 特に 公式サイトのhistoryのページ
全訳!fishシェル普及計画
→特に 全訳!fishシェル普及計画のhistoryのページ
fish-shellのGithubのページ
bash
のhistory
について
コマンド履歴を表示するhistoryコマンドを詳しく!【Linuxコマンド集】
コマンド履歴の達人を目指してみる