LoginSignup
0
1

More than 5 years have passed since last update.

fishからbashのletを呼び出してちょっと計算する

Posted at

はじめに

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便利.

0
1
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
0
1