はじめに
fishでは,計算は基本的にmath
コマンドにやってもらうことになっています.
なのでwhile
ループ時のインクリメント等は
set i 0
while true
# do something
set i (math $i + 1)
end
と書きます.ループカウンターみたいに短い名前の変数なら問題ないのですが,変数名が長いと
set __my_function_search_count (math $__my_function_search_count + 1)
みたいになってつらい.ただのインクリメントなので短く書きたいです.
解決
インクリメントをする方法,bashだと色々あるらしいのですが,bashビルトインのlet
コマンドを使う方法だと
let __my_function_search_count++
でインクリメントでできるようです.
これをfishでも利用すべく,let
コマンドのラッパーを書いてみました.
let.fish
function let --no-scope-shadowing
if not string match -qr '^\w+' -- "$argv" # 変数名が与えられていないとき
bash -c "let $argv[1]" # エラーメッセージを吐かせて終了 `let --help`もここで処理
return $status
end
if string match -qr '^argv\W' -- "$argv" # 変数がargvのとき
set -l expr (string match -r '(\w+)(.*)' -- "$argv")
set -e argv # これで呼び出し側のargvが見える
set argv (bash -c "v=$$expr[2]; let v$expr[3]; echo \$v")
else # それ以外の変数のとき
set argv (string match -r '(\w+)(.*)' -- "$argv")
set $argv[2] (bash -c "v=$$argv[2]; let v$argv[3]; echo \$v")
end
end
これを使うと,fishでも次のような書き方ができます.
set -l foo 0 # setで変数を定義して...
let foo++ # インクリメント
let foo+=3 # 増分指定
let foo=$foo%3 # 剰余
set -l __long_long_long_name 0
let __long_long_long_name++ # 長い名前でも比較的見やすい!...かも?
プラグイン化もしたので,他のプラグインを書くときにも利用可能です.
終わりに
bashを使ってfishのローカル変数の書き換え...できるのか? といろいろ試した結果,できました.ポイントは
-
--no-scope-shadowing
オプションで関数外のローカル変数を書き換える. - 任意の変数名に対応するため,極力
argv
以外のローカル変数を定義しない. - 書き換えるのが
argv
である場合は,let
関数内のargv
を消して一段階外側を参照する.
です.ブレース展開に続き,bashの力でfishを便利にするシリーズでした.bash便利.