LoginSignup
15
12

More than 3 years have passed since last update.

[fish-shell] ご注文はcdしたら自動でlsですか?

Last updated at Posted at 2016-12-06

fish-shell始めて2日目です。
いきなり躓いたので、ちょっと書いとこうと。

fishさん、基本的にはaliasさえ設定すれば、他は何もしなくてもいいぐらい出来のいいシェルっぽいです。
あまり深くは知らないんですけど。。。
でも、一点だけアレだったのでスクリプト書きました。

cdしたらlsしたいですよね。
あれ?もうcdしたらlsする手癖が付いてる?
そういうのは、自動化しましょ。ね?

で、alias cd = "my_cd; and ls"ってやってみたものの何故か移動してくれない。
でもlsはちゃんと移動後のパスでやってくれてる。
なんでだーーー!!!ってなったんですが、関数作ってやればいいんですね。
気付くまで結構時間かかりました(´・_・`)

config.fish
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さん

追加でこんな仕様にしてます。
1. 引数が0の時にホームディレクトリに行っちゃうのが嫌だったので、なにもせず正常終了する。
2. 存在しないディレクトリを指定して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

さっきの見出しで言った移動履歴機能です。
ちょっと長いので箇条書きで書いていきます。

  1. if test $cd_status -eq 0 -a "$PWD" != "$previous"
    cdコマンドの実行結果が成功であることを判定してるのは分かると思いますが、 今の「カレントディレクトリ」と「さっき居たディレクトリ」が同じかも判定してます。
    同じだったら動いてないと判断して履歴に残さないようになってます。
  2. set -q dirprev[$MAX_DIR_HIST]
    履歴管理変数が存在することを確認します。
  3. set -e dirprev[1]
    履歴管理変数の先頭を削除します。
    Fishは配列が1始まりであることに注意しましょう。
  4. set -g dirprev $dirprev $previous
    履歴管理変数に今回の結果を保存します。
  5. set -e dirnext
    新しい場所に移動したため「次」は持ってません。
    dirnextを削除します。
  6. set -g __fish_cd_direction prev
    これもちょっとよく分からないんですけど、次のコードでcd -の挙動を制御してます。
    cd -で「前に戻る」のか「先に行く(前の前に戻る)」のかを制御するために方向を制御していそうです。
    if test "$argv" = "-"
        if test "$__fish_cd_direction" = "next"
            nextd
        else
            prevd
        end
        return $status
    end
    ```

15
12
1

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
15
12