LoginSignup
13
5

More than 5 years have passed since last update.

fishでも{1..9}を展開したい!

Last updated at Posted at 2017-03-25

tl;dr

fishシェルで擬似的にecho {1..9}のような範囲展開を実現するプラグインを作成しました.

動機

fishシェル便利ですよね! 素の設定でかなり快適に使うことができます.
しかし,他のシェルと比べて不便だなと思う点もあります.

スクリーンショット 2017-03-25 15.39.36.png

どうやら,fishのブレース展開は{1..9}{a..c}のような範囲展開ができないようです.

fishで範囲展開に相当することを行うにはコマンド置換を使います.

# {1..9}相当
touch test(seq 9).txt

# {1..9..2}相当
echo (seq 1 2 9).txt

# {a..c}相当
echo (jot -c 3 a c)

このように一応可能ではある...ものの,タイプ量も増えるし,これまで通り{1..9}の書式で範囲展開できないかな...と考えていました.

解決

fishcommandlineコマンドについて調べていた際にアイデアを思いついたので実装してみました.擬似的にですがfishで範囲展開が可能になります.

fish_expand_range.mov.gif

fish{1..9}といった書式を受け付けてくれない以上,入力したコマンドが実行される前に,その内容を書き換えるしかないという発想です.

実装を要約すると以下の通りです.コマンドの実行を行う改行キー(\n, \r)にキーバインドして,コマンドラインの内容を書き換えます1.

key_bindings.fish
bind \n 'type -q __expand_range; and __expand_range; commandline -f execute'
bind \r 'type -q __expand_range; and __expand_range; commandline -f execute'
__expand_range.fish
function __expand_range
    set -l buf
    for line in (commandline) # コマンドラインが複数行だった場合のためのループ
        set buf $buf (expand_range $line) # これが処理の本体
    end
    commandline (string join \n $buf) # 複数行をつなげてコマンドラインに書き出す.
end

ちなみに範囲展開そのもの(expand_range関数)の実装についてですが,bashを呼んで展開してもらっています.

bashを呼んで展開してもらっています.

つまり実体はbash -c 'echo {1..9}'です.bash便利.

まとめ

fishシェルはbashzshのような多機能性と引き換えにシンプルな姿を得たシェルですが,bashの機能をつまみ食いすることで,もっと便利に使えるようになりました.

余談

改行にキーバインドするという荒っぽい方法ですが,いろいろ可能性はありそうです.
というのも,上記__expand_range.fish関数内で呼び出しているexpand_range関数を任意の文字列操作コマンドに変えることにより,対話モードに限って好きな構文を擬似的に追加できるからです.

すぐ思いつくところでは,以下のようなもがあります.

  • コマンドラインにGを見つけたら| grepに置換 (zshのglobal alias相当)
  • 最初の語が実行可能でないファイルのとき,拡張子を見て適当なコマンドを前置 (zshのsuffix alias相当)
  • !!eval $history[1]に置換 (ヒストリ置換相当)
  • コマンドラインが特定の条件を満たすとき,空白を前置してヒストリに残さない (bashHISTIGNORE相当)
  • コマンドライン中の重複した空白を一つにしてから実行 (zshhist_reduce_blanks相当)
  • $((...))(math ...)に置換
  • &&; andに,||; orに置換

もちろん,上記全部を実装するくらいなら初めからzshを使え,という話になるのですが,「fishには概ね満足だが,他のシェルにあるあの機能がないのが我慢できない」という場合は,必要な機能だけつまみ食いして追加できる可能性が,あるのではないでしょうか...

追記(2017/4/1)

改行へのキーバインドによってグローバルエイリアスを実現する,を既にやっている方がおられました!
zshからfishに乗り換えてみた


  1. キーバインドで一つの関数を呼び出すのではなく,;で分割して複数コマンド呼び出しているのは,関数が削除された場合のための保険です.他のキーならともかく,改行を失うことになると大変なので. 

13
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
5