fish-shell始めて2日目です。
いきなり躓いたので、ちょっと書いとこうと。
fishさん、基本的にはaliasさえ設定すれば、他は何もしなくてもいいぐらい出来のいいシェルっぽいです。
あまり深くは知らないんですけど。。。
でも、一点だけアレだったのでスクリプト書きました。
cd
したらls
したいですよね。
あれ?もうcd
したらls
する手癖が付いてる?
そういうのは、自動化しましょ。ね?
で、alias cd = "my_cd; and ls"
ってやってみたものの何故か移動してくれない。
でもlsはちゃんと移動後のパスでやってくれてる。
なんでだーーー!!!ってなったんですが、関数作ってやればいいんですね。
気付くまで結構時間かかりました(´・_・`)
function cd
if test (count $argv) -eq 0
return 0
else if test (count $argv) -gt 1
printf "%s\n" (_ "Too many args for cd command")
return 1
end
# Avoid set completions.
set -l previous $PWD
if test "$argv" = "-"
if test "$__fish_cd_direction" = "next"
nextd
else
prevd
end
return $status
end
builtin cd $argv
set -l cd_status $status
# Log history
if test $cd_status -eq 0 -a "$PWD" != "$previous"
set -q dirprev[$MAX_DIR_HIST]
and set -e dirprev[1]
set -g dirprev $dirprev $previous
set -e dirnext
set -g __fish_cd_direction prev
end
if test $cd_status -ne 0
return 1
end
ls
return $status
end
bashだとbuiltinコマンドは、\cd
って書いてたんですが、
builtin cd
だと見直した時に分かり易いですね。
さすがfishさん
追加でこんな仕様にしてます。
- 引数が0の時にホームディレクトリに行っちゃうのが嫌だったので、なにもせず正常終了する。
- 存在しないディレクトリを指定してcdに失敗したら、lsは実行せず異常終了する。
移動に失敗したのに、lsされてもねぇ?
他の長い処理はデフォルト設定のままですね。
以下、追記
かれこれ「やっぱりBashやで」ってなってBash使ってたんですけど、Macに移行する際にFishに戻ってきました。
というのも、MacOSのBashはライセンスの関係上更新できないようでかなり古くて、かと言って上書きも怖いなーってなったからです。
で、ちょっとcdコマンドを読んでて、「あー昔はよく分からなかったけど、こんなことしてるんだ」ってのがわかったので追記。
Bashのライセンスが非常に強烈で超絶簡単に説明すると「Bashを使ったら、リンクしてるコードもフリーソフトさせろ」みたいになってるようです。MacOS自体をフリー化させる訳にはいかないAppleは新しいBashを採用できないんですね。
GNUにも言い分はあるんでしょうが、営利企業の事情を完全無視してるちょっと不便なライセンスですね。
prevdを使わない理由
# Avoid set completions.
set -l previous $PWD
ここなんですけど、Bashでいう$OLDPWDを設定している箇所です。
Fishには過去の移動履歴を管理するprevd
コマンドと環境変数dirprev
がいるんですけど、なんでそれを使わないのかなーって思ってました。
自分で書き換えてうまく動かなかったことでわかったんですけど、dirprev
に代入する処理は後段の処理がになってるんですけど、そこで初めて代入されます。
つまり、Fish shell起動直後の1回目のcd
コマンドの段階ではprevd
は動いてないんですよ。
ということで、prevd
が使えないのでcdする前にカレントパスを保存するという方法を使ってるんですね
ロギング機能
# Log history
if test $cd_status -eq 0 -a "$PWD" != "$previous"
set -q dirprev[$MAX_DIR_HIST]
and set -e dirprev[1]
set -g dirprev $dirprev $previous
set -e dirnext
set -g __fish_cd_direction prev
end
さっきの見出しで言った移動履歴機能です。
ちょっと長いので箇条書きで書いていきます。
-
if test $cd_status -eq 0 -a "$PWD" != "$previous"
cd
コマンドの実行結果が成功であることを判定してるのは分かると思いますが、
今の「カレントディレクトリ」と「さっき居たディレクトリ」が同じかも判定してます。
同じだったら動いてないと判断して履歴に残さないようになってます。 -
set -q dirprev[$MAX_DIR_HIST]
履歴管理変数が存在することを確認します。 -
set -e dirprev[1]
履歴管理変数の先頭を削除します。
Fishは配列が1始まりであることに注意しましょう。 -
set -g dirprev $dirprev $previous
履歴管理変数に今回の結果を保存します。 -
set -e dirnext
新しい場所に移動したため「次」は持ってません。
dirnext
を削除します。 -
set -g __fish_cd_direction prev
これもちょっとよく分からないんですけど、次のコードでcd -
の挙動を制御してます。
cd -
で「前に戻る」のか「先に行く(前の前に戻る)」のかを制御するために方向を制御していそうです。if test "$argv" = "-" if test "$__fish_cd_direction" = "next" nextd else prevd end return $status end