なぜfishを選ぶ?

fishはフル装備のコマンドラインシェル(bashやzsh同様)で、賢くユーザフレンドリーです。
fishは シンタックスハイライトオートサジェスチョン 、知識ゼロ・設定ゼロでそのまま動作する TAB補完 をサポートしています。

もし、コマンドラインをもっと生産的に、便利に、楽しい(難解な文法や設定オプションを学ぶことなく)環境にしたいならば、fishはあなたの求めていたシェルかもしれません!

fishを学ぶ

このチュートリアルはコマンドラインシェルやUnixコマンドの知識があり、fishがインストールされていることを前提とします。

もし、他のシェルについての深い理解があり、fishとの相異点を知りたいならば、 「 他のシェルと違って 」 という魔法の語句を検索してください。
それは重要な相異点を表してます。

fishを立ち上げると、このように表示されます。

Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
you@hostname ~>

fishではデフォルトのプロンプトとして、ユーザー名、ホスト名、カレントディレクトリを表示します。
このプロンプトを変更する方法は後述します。
とりあえず現時点では、スペースを節約するため単純に「> 」をプロンプトだと仮定します。

コマンドを実行する

fishは他のシェルと同様にコマンドを実行します。
つまり、あなたはコマンドと引数を打ち込みます。
スペースはセパレータです。

> echo hello world
hello world

スペースを引数として渡すには、バックスラッシュを前置するか、シングルクォートかダブルクォートで囲みます。

> mkdir My\ Files
> cp ~/Some\ File 'My Files'
> ls "My Files"
Some File

コマンドはセミコロンでつなげます。

ヘルプを見る

fishは素晴しいヘルプとmanページを塔載しています。
help コマンドを実行するとWebブラウザでヘルプを開きます。
man コマンドはmanページを開きます。
また、特定のコマンドについてのヘルプを見ることもできます。
たとえば、「help set」を実行するとWebブラウザで、「man set」を実行すると端末でヘルプを表示します。

> man set
set - handle shell variables
  Synopsis...

シンタックスハイライト

fishにコマンドを打ち込んでいるとシンタックスハイライトが働いていることに、あなたはすぐに気付くでしょう。
無効なコマンドはデフォルトでは赤色で表示されます

> /bin/mkd

コマンドは、存在しないか実行可能でない場合に無効になります。
コマンドが有効になったときは、色が変わります。

> /bin/mkdir

fishはファイル名として妥当であるとき、アンダーラインを引きます。

> cat ~/somefi

アンダーラインは、somefiから始まるファイルが存在することを示します。
それは、タイプ中においては便利なフィードバックです。

fishで使われる色は fish_config コマンドを実行するか、変数を直接修正することで変更できます。

ワイルドカード

fishはよく使うワイルドカード「*」をサポートしています。
すべてのJPEGファイルをリストするには、

> ls *.jpg
lena.jpg
meena.jpg
santa maria.jpg

複数のワイルドカードも使えます。

> ls l*.p*
lena.png
lesson.pdf

特に強力なのは、サブディレクトリを再帰的にたどるワイルドカード「**」です。

> ls /var/**.log
/var/log/system.log
/var/run/sntp.log

もしディレクトリ探索に時間がかかるときは、Ctrl+Cで中止できます。

パイプとリダイレクト

「|」でコマンド間をパイプできます。

> echo hello world | wc
       1       2      12

標準入力と標準出力は使い慣れている「<」と「>」でリダイレクトできます。
他のシェルと違って 標準エラー出力は「^」でリダイレクトします。

> grep fish < /etc/shells > ~/output.txt ^ ~/errors.txt

オートサジェスチョン

fishは打ち込んだコマンドをサジェスチョンします。
サジェスチョンはカーソルの右に灰色で表示します。
たとえば、

> /bin/hostname

サジェスチョンはパスやオプションについても働きます。

> grep --ignore-case

サジェスチョンはコマンドライン履歴についても働きます。
一度コマンドを実行したら、数文字打ち込んだだけで過去のコマンドを呼び出せます。

> rsync -avze ssh . myname@somelonghost.com:/some/long/path/doo/dee/doo/dee/doo

オートサジェスチョンを受け入れるには、→かCtrl+F(訳注:Ctrl+Eも使える)を押します。
オートサジェスチョンで示されたうち、1語のみを受け入れるには、Alt+→(訳注:Alt+Fも使える)を押します。
もしオートサジェスチョンが望むものではない場合は、ただ無視すればいいです。

TAB補完

fishは『そのまま動作する』多種類のTAB補完機能があります。

TABを押してください。
すると、fishはコマンド、引数、パスを補完しようとします。

> /pri [TAB] → /private/

2つ以上の候補があるときは、それらをリストします。

> ~/stuff/s @key{Tab}
~/stuff/script.sh  (Executable, 4.8kB)  ~/stuff/sources/  (Directory)

TABをもう一度押すと、候補間をサイクルします。

fishは多くのコマンドを補完します、たとえばgitのブランチとか。

> git merge pr @key{Tab} → git merge prompt_designer
> git checkout b @key{Tab}
builtin_list_io_merge (Branch) builtin_set_color (Branch) busted_events (Tag)

もっとTABを押してfishがどう動作するかを見てください!

変数

他のシェル同様、「$」で変数置換を行ないます。

> echo My home directory is $HOME
My home directory is /home/tutorial

変数置換はダブルクォートの中でも行われますがシングルクォートでは行われません。

> echo "My current directory is $PWD"
My current directory is /home/tutorial
> echo 'My current directory is $PWD'
My current directory is $PWD

他のシェルと違って 、fishは変数への代入構文を持っていません。
代入は通常のコマンドである set を使います。
setコマンドに変数名とその値を渡します。

> set name 'Mister Noodle'
> echo $name
Mister Noodle

(クオートが付いていることに気付いてください。
クオート無しだとMisterとNoodleは別々の引数になり、$nameは2要素のリストになります。
(訳注:引数の渡り方についてはargs自作関数 を使えばわかります))

他のシェルと違って 変数は置換後に分割されません。

> mkdir $name
> ls
Mister Noodle

bashではMisterとNoodleの2つのディレクトリを作成します。
fishでは1つ("Mister Noodle"という値の変数)のディレクトリを作成します。
"Mister Noodle"はスペースも含めてmkdirに1つの引数として渡されます。
他のシェルではリストではなくてarray(配列)という用語を使っています。

終了ステータス

他のシェルと違って 、fishは「$?」ではなくて「 $status 」に最後に実行したコマンドの終了ステータスを格納します。

> false
> echo $status
1

0が成功、1以上が失敗です。

環境変数

他のシェルと違って 、fishは export コマンドがありません。
その代わり set コマンドに「--export」か「-x」オプションを付けてexport(訳注:環境変数化)します。

> set -x MyVariable SomeValue
> env | grep MyVariable
MyVariable=SomeValue

「-e」または「--erase」オプションで変数を削除します。

> set -e MyVariable
> env | grep MyVariable
(no output)

リスト

上記のsetコマンドではクオートを使って Mister Noodle を1つの引数として扱いました。
2つの引数を持ったならば、その変数は2要素のリストになります。
実際fishのすべての引数はリストであり、0個以上無制限の値を格納できます。

$PWD などいくつかの変数はたった1つの値を持ちます。
便宜上、「変数の値」と言った場合は最初(あるいは唯一)の値を意味することにします。

$PATH など他の変数は複数の値を持ちます。
変数展開中は、変数は複数の引数へと展開します。

> echo $PATH
/usr/bin /bin /usr/sbin /sbin /usr/local/bin

リストは他のリストを含むことができません、つまり再帰的ではありません。
変数は文字列のリストだけとなります。

count コマンドでリストの長さを得ます。

> count $PATH
5

リストの前か後に値を追加するには、新しい引数をリストそのものに設定します。
たとえば、以下のようにして /usr/local/bin を $PATH に追加します。

> set PATH $PATH /usr/local/bin

リストの各要素は[ ]を使ってアクセスします。
インデックスは 1から始まり 、-1で最後尾となります。

> echo $PATH
/usr/bin /bin /usr/sbin /sbin /usr/local/bin
> echo $PATH[1]
/usr/bin
> echo $PATH[-1]
/usr/local/bin

引数の範囲はスライスとしてアクセスします。

> echo $PATH[1..2]
/usr/bin /bin
> echo $PATH[-1..2]
/usr/local/bin /sbin /usr/sbin /bin

リストかスライスは for ループが使えます。

> for val in $PATH
    echo "entry: $val"
  end
entry: /usr/bin/
entry: /bin
entry: /usr/sbin
entry: /sbin
entry: /usr/local/bin

隣り合わせのリストや文字列群は、クオートしないと デカルト積 として展開されます。(変数展開 参照)

> set -l a 1 2 3
> set -l 1 a b c
> echo $a$1
1a 2a 3a 1b 2b 3b 1c 2c 3c
> echo $a" banana"
1 banana 2 banana 3 banana
> echo "$a banana"
1 2 3 banana

これは {}展開 に似ています。

コマンド置換

コマンド置換は1つのコマンドの出力を別なコマンドの引数として使う機能です。
他のシェルと違って 、fishはバッククォートのかわりに()を使います。

> echo In (pwd), running (uname)
In /home/tutorial, running FreeBSD

よくある使い方は、コマンド出力を変数に代入することです。

> set os (uname)
> echo $os
Linux

コマンド置換はクオートの中では行われません。
その代わり、一旦クオートを閉じてからコマンド置換を行って、再度クオートを開いてください。
そうすることですべて同じ引数になります。

> touch "testing_"(date +%s)".txt"
> ls *.txt
testing_1360099791.txt

論理(and, or, not)

他のシェルと違って 、fishは「&&」や「||」のような特殊な文法は使いません。
その代わり andornot というコマンドを使います。

> cp file1.txt file1_bak.txt; and echo "Backup successful"; or echo "Backup failed"
Backup failed

条件分岐(if, else, switch)

終了ステータスに基く条件分岐には ifelse ifelse を使います。

if grep fish /etc/shells
    echo Found fish
else if grep bash /etc/shells
    echo Found bash
else
    echo Got nothing
end

switch コマンドもあります。

switch (uname)
case Linux
    echo Hi Tux!
case Darwin
    echo Hi Hexley!
case FreeBSD NetBSD DragonFly
    echo Hi Beastie!
case '*'
    echo Hi, stranger!
end

fishの case コマンドはfall through(訳注:C言語がするように)しません。
また、caseコマンドは複数の引数やクォートされたワイルドカードも受け付けます。

シェル関数

fishの関数はコマンドのリストで、引数を持つことができます。
他のシェルと違って 、引数には $1 などのような数字変数ではなくて1つのリスト $argv でアクセスします。
関数を定義するには function ビルトインを使います。

> function say_hello
     echo Hello $argv
  end
> say_hello
Hello
> say_hello everybody!
Hello everybody!

他のシェルと違って 、fishはaliasや特殊なプロンプトの文法を持ちません。
関数がそれらの役割を果たしています。

全ての関数名のリストは functions (複数形!)キーワードで得られます。
fishでは最初からたくさんの関数が定義されています。

> functions
alias, cd, delete-or-exit, dirh, dirs, down-or-search, eval,
export, fish_command_not_found_setup, fish_config,
fish_default_key_bindings, fish_prompt, fish_right_prompt,
fish_sigtrap_handler, fish_update_completions, funced, funcsave,
grep, help, history, isatty, ls, man, math, nextd,
nextd-or-forward-word, open, popd, prevd, prevd-or-backward-word,
prompt_pwd, psub, pushd, seq, setenv, trap, type, umask, up-or-search, vared

functionsに関数名を渡すことで、関数のソースコードが得られます。

> functions ls
function ls --description 'List contents of directory'
    command ls -G $argv
end

ループ

while ループ。

> while true
    echo "Loop forever"
end
Loop forever
Loop forever
Loop forever
...

for ループはリストの各要素を反復処理します。
たとえば、ファイルのリストとか。

> for file in *.txt
    cp $file $file.bak
end

seq コマンドと併用すれば数列でループできます。

> for x in (seq 5)
    touch file_$x.txt
end

プロンプト

他のシェルと違って 、fishにはPS1のようなプロンプト変数は存在しません。
fishではプロンプトを表示するために、 fish_prompt 関数を実行し、その出力をプロンプトとして使います。

あなた独自のプロンプトを定義できます。

> function fish_prompt
    echo "New Prompt % "
end
New Prompt %

複数行でもOKです。
色は set_color コマンドにANSIカラーか16進数RGBを渡して設定します。

> function fish_prompt
      set_color purple
      date "+%m/%d/%y"
      set_color FF0
      echo (pwd) '>'
      set_color normal
  end
02/06/13
/home/tutorial >

fish_config コマンドを実行させれば、プロンプトをサンプルから選択できます。
fishは fish_right_prompt 関数を通じて右プロンプトをサポートします。

$PATH

$PATH はfishがコマンドを探すディレクトリを含む環境変数です。
他のシェルと違って 、$PATHはリストであって、コロン区切りの文字列ではありません。

/usr/local/binと/usr/sbinを $PATH に加えるには、以下のように書きます。

> set PATH /usr/local/bin /usr/sbin $PATH

他のシェルの ~/.profile でやるように、上記を直接 config.fish (訳注:~/.config/fish/config.fish) に書き加えることができます。
以下の例を見てください。

より手っ取り早い方法は $fish_user_paths ユニバーサル変数を変更することです。
これは自動的に $PATH の前に付け加えられます。
たとえば、恒久的に /usr/local/bin を $PATH に加えたければ、以下のように書けます。

> set -U fish_user_paths /usr/local/bin $fish_user_paths

この方法の利点は、ファイルをいじくる必要がないことです。
コマンドラインで一度だけ実行すれば、現在のfishセッションそして将来にわたって効力を発揮します。
(注意:上記はconfig.fishに書き加え「ない」でください。
もしそうしたら、fishを立ち上げるたびに長くなってしまいます。)

立ち上げ

fishは ~/.config/fish/config.fish を実行してから立ち上がります。
もし存在しなければ自分で作成することができます。

これまで述べたコマンド(訳注:functionやset)でconfig.fish内で直接関数や変数を定義することができます。
たとえば、

> cat ~/.config/fish/config.fish

set -x PATH $PATH /sbin/

function ll
    ls -lh $argv
end

しかし、オートロード関数とユニバーサル変数を使うのが通例で、しかも効率的です。

オートロード関数

fishがコマンドを発見したとき、 ~/.config/fish/functions/ 以下でコマンド名で名付けられたファイルを検索し、そのコマンドをオートロード関数として呼び出そうとします。

たとえば、関数 ll を定義したければ、 ~/.config/fish/functions/ll.fish に書きます。

> cat ~/.config/fish/functions/ll.fish
function ll
    ls -lh $argv
end

あなた独自のプロンプトを定義する良い方法は ~/.config/fish/functions/fish_prompt.fish を作成することです。

> cat ~/.config/fish/functions/fish_prompt.fish
function fish_prompt
    echo (pwd) "> "
end

これらのファイルを自動的に作るには、funcedfuncsave のドキュメントを参照してください。

ユニバーサル変数

ユニバーサル変数とは、すべてのfishセッション(今も将来も、リブート後さえも)間で共有する変数です。
set -U でユニバーサル変数を定義します。

> set -U EDITOR vim

他のfishにおいて実行すると…

> echo $EDITOR
vim

もっと知るには

もっとfishについて知りたいならば、詳細ドキュメント公式メーリングリスト 、 irc.oftc.net の #fish IRCチャネル、 githubページ を参照してください。

最後までお読みいただき、ありがとうございました。参考になれば嬉しいです。