BashユーザのためのFish
概要
Fishは、POSIX互換ではないため、Bash等の他のシェルとは異なる動作をするものがある。
いずれのシェルも、基本的にコマンドラインの拡張、パイプ、リダイレクト、変数、グロブを備えており、様々な方法でコマンド出力を使用する。
コマンドの置換
Fishはコマンド置換を、$(command)、または、(command)と記述する。
また、Fishには、$IFSは存在せず、改行で分割する。
それ以外の方法で分割する場合は、splitコマンド、string split0コマンド、string collectコマンドのいずれかを使用する。
詳細は、Fishの基礎 - 繰り返し文#for文を参照すること。
変数
Fishは、setコマンドにより変数の設定や消去を行う。
また、declareコマンド、unsetコマンド、exportコマンド等の様々な個別の組み込みを行う。
例えば、setコマンドは、オプションで変数のスコープやエクスポートの可否を決定する。
# 変数PAGERをグローバルに定義およびエクスポートすることにより、export PAGER=lessと同様になる
set -gx PAGER less
# alocalvariable=fooのように、$alocalvariableをローカルにのみ定義する
set -l alocalvariable foo
変数を消去する。
set -e PAGER
<変数名>=<値>文は、環境のオーバーライドとして利用できる。
PAGER=cat git log
Fishは、単語の分割を行わないため、変数に値が設定されると、その値はそのまま維持される。
そのため、Bashのように変数の展開をダブルクオートで記述する必要はない。
# Bashの場合
# ダブルクォートを使用していないため、ワードスプリッティング(2行で表示)となる
foo="bar baz"
printf '%s\n' $foo
# 出力
bar
baz
# Fishの場合
# 変数fooは1つの要素として設定されているため、1つの要素として渡される (1行で表示される)
set foo "bar baz"
printf '%s\n' $foo
# 出力
foo baz
変数は全て配列(リスト)であるため、変数を展開するとその全ての要素が展開される。
配列の各要素は、それ自身の引数となる。(Bashでいう${var[@]}と同様)
set var "foo bar" banana
printf '%s\n' $var
# 出力
foo bar
banana
リストの特定の要素を選択することができます。
echo $list[5..7]
setコマンドを使用して、コマンドの出力に変数を設定することも可能である。
# 変数lineにfile.txtファイル内の全ての内容を設定して、1行に1つの要素を設定する
set lines (cat file.txt)
リテラル値とコマンドを混在させて、変数に代入することも可能である。
set numbers 1 2 3 (seq 5 8) 9
printf '%s\n' $numbers
# 出力
1
2
3
5
6
7
8
9
set <変数名> = <値>コマンドは間違ったシンタックスであり、変数に2つの値(=と<値>)を代入してしまう。
ワイルドカード
Fishは、構文として*グロブおよび**グロブ(および非推奨の?グロブ)のみをサポートしている。
ただし、for文、set、count、グロブが変数オーバーライド(set VAR *文等)が使用されている場合は、(Bashのnullglobオプションのように)何もない状態に展開される。
グロブは展開された変数では適用されないため、以下に示すような記述は、どのファイルにもマッチしない。
set foo "*"
echo $foo
引用符で囲まれていない*、または、?が含まれている場合、それをワイルドカードとして使用することができる。
- *
- ファイル名に含まれる任意の文字数(0を含む)にマッチする。(
/は含まれない)
- ファイル名に含まれる任意の文字数(0を含む)にマッチする。(
- **
- 任意の数の文字(0を含む)に再帰的にマッチする。(サブディレクトリは降順)
- 自身のセグメントである場合は、他のシェルとの互換性のために、そのセグメントもマッチする可能性がある。
- ?
- /以外の任意の1文字にマッチする。
- ただし、
?の使用は非推奨であり、qmark-noglob機能フラグで無効にできるため、?は通常の文字として扱うことができる。
ワイルドカードのマッチは、大文字小文字を区別せずにソートされる。
数字を含むマッチをソートする場合、それらは自然にソートされて、'1'、'5'、'12'という文字列は1,5,12のようにソートされる。
隠しファイル(名前がドットで始まるもの)は、ワイルドカードの文字列がその場所にドットを持たない限り、ワイルドカードを使用する際に考慮されない。
- a*
- 現在のディレクトリにある'a'で始まる全てのファイルにマッチする。
- **
- カレントディレクトリとそのサブディレクトリにある全てのファイルとディレクトリにマッチする。
- ~/.*
- ホームディレクトリにある全ての隠しファイルとディレクトリにマッチする。
多くのコマンドでは、ワイルドカードの展開に失敗する時、コマンドは実行されずに環境変数statusが0以外に設定されて、警告が表示される。
この動作は、Bashがshopt -s failglobで行うのと同様である。
例外として、set、path、overrides文での変数のオーバーライド、count文、for文がある。
これらのグロブは、Bashのshopt -s nullglobのように、引数ゼロに展開される。
# .txtファイルをリストアップして、存在しない場合は警告を表示する
ls *.txt
# .txtファイルが存在する場合は、その一覧を表示する
set foos *.txt
if count $foos >/dev/null
ls $foos
end
Bashとは異なり、Fishは(デフォルトでは)マッチしない場合、リテラルなグロブ文字を渡さないため、
findコマンドやsudo zypper installのようにマッチング自体を行うコマンドでは、引用符を追加する必要がある。
sudo zypper install "ncurses-*"
find . -iname "*.txt"
引用符
Fishには、2つの引用符""と''がある。
変数はダブルクォートで展開されて、引用符が無い場合はシングルクォートで展開される。
また、$は存在しないが、変換されるようなシーケンスはクォートされていない時に変換される。
echo a\nb
# 出力
a
b
パラメータ展開や文字エスケープの機能を無視する場合、'または"を使用する。
'の間では、Fishは展開を行わない。
"の間では、Fishは変数の展開のみを行う。
他の種類の展開(波括弧の展開やパラメータの展開を含む)は行われず、エスケープシーケンス(例. \n)は無視される。
引用符の中では、引数の区切りに空白を使用しないため、引用符で囲まれた引数に空白を含めることができる。
'をエスケープする場合は\'、"をエスケープする場合は\"、ドル文字をエスケープする場合は\$、バックスラッシュと改行を削除する場合は\、バックスラッシュ記号をエスケープする場合は\\である。
'は"内では特別な意味を持たないが、その逆も同様である。
# "cumbersome filename.txt"という名前のファイルを削除する
rm "cumbersome filename.txt"
# "cumbersome"ファイルと"filename.txt"ファイルの2つのファイルを削除する
rm cumbersome filename.txt
# foo.txtファイルの内容から、enabled)で終わる行を検索する
# (grepコマンドにおいて、$記号は行末にマッチする)
grep 'enabled)$' foo.txt
文字列の操作
Fishの文字列の操作は、stringコマンド(組み込み関数)により行われる。
"bar "を"baz "に置換する。
string replace bar baz "bar luhrmann"
# 出力
baz luhrmann
文字列を分割する。
string split "," "foo,bar"
# 出力
foo
bar
grepコマンドの代替として、正規表現にマッチする。
echo bababa | string match -r 'aba$'
# 出力
aba
文字列を任意の文字で、指定された幅になるように埋める。
string pad -c x -w 20 "foo"
# 出力
xxxxxxxxxxxxxxxxxfoo
文字列を小文字または大文字にする。
# 小文字に変換する
string lower Foo
# 出力
foo
# 大文字に変換する
string upper Foo
# 出力
FOO
その他、文字列のリピート、文字列のトリム、文字列のエスケープ、文字列の長さや幅の表示(端末セル単位)を行うこともできる。
特殊な変数
下表に、FishとBashの特殊な変数の比較を示す。
| Bash | Fish |
|---|---|
| $* $@ |
$argv |
| $1 $2 |
$argv[1] $argv[2] |
| $? | $status |
| $$ | $fish_pid |
| $# | Fishには存在しないため、count $argvコマンドを使用する。
|
| $! | $last_pid |
| $0 | Fishには存在しないため、status filenameコマンドを使用する。
|
| $- | Fishには存在しないため、status is-interactiveまたはstatus is-loginを使用する。
|
ヒアドキュメント
Fishは、<<EOF文は存在しないため、printf文、または、""と改行を使用して、ヒアドキュメントを行う。
printf %s\n "some string" "some more string"
# または
echo "some string
some more string"
# または、引用符を別の行にする場合
echo "\
some string
some more string\
"
ヒアドキュメントが行うことを、以下に示す。
- 文字列を特殊なルールで終端まで読み取り、解釈する。
- 結果の文字列を一時ファイルに書き出す。
- そのファイルを標準入力として、ヒアドキュメントが添付されているコマンドを起動する。
ヒアドキュメントと同様に、コマンドはstdinから読み込むように準備しなければならない。
これには特別なオプションが必要なこともあり、多くの場合、ファイル名を-で与えることにより有効になる。
echo "xterm
rxvt-unicode" | sudo zypper remove -
# 以下に示すコマンドと同様である
# -は、zypperが標準入力から引数を読み込むようにしている
sudo zypper remove xterm rxvt-unicode
ヒアドキュメントは、多くの特殊なルールを導入するマイナーな構文上の味付けに過ぎないため、Fishではパイプを使用することにより、簡潔に記述・構成することができる。
算術演算
Fishでは、算術演算はmathコマンドにより処理される。
math $i + 1
他のシェルの算術演算と異なり、Fishでは浮動小数点数を扱うことができる。
math 5 / 2
# 出力
2.5
三角測量のような機能も存在する。
math cos 2 x pi
# 出力
1
mathコマンドの引数は、別々に渡す、または、引用符で囲んで渡すことができる。
Fishは、コマンド実行に()を使用するため、式の中で使用する場合は、引用符で囲む必要がある。
math '(5 + 2) * 4'
*とxは両方ともFishにおける乗算記号であるが、*を使用する場合は、引用符で囲む必要がある。(グロブに見えるため)
プロンプト
Fishは、$PS1や$PS2等の特殊変数は存在しない。
fish_prompt関数の出力、または、vi-modeが有効な場合はfish_mode_prompt関数、右プロンプトの場合はfish_right_prompt関数を加えたものが使用できる。
- テキストに色を付けるため、
set_colorを提供している。
これは、16色の名前付きカラーやRGBカラー(例.set_color 5555FF)を使用することができる。 - プロンプトに何かを追加するためのヘルパー関数が存在する。
- 例1. バージョン管理システム(git、mercurial、svn)の表示を追加する
fish_vcs_prompt関数 - 例2. 現在の場所(ユーザのホームディレクトリは
~になり、パスの構成要素が全て短縮される)を表示するprompt_pwd関数 - 例3. ホスト名を短縮して表示する
prompt_hostname関数
- 例1. バージョン管理システム(git、mercurial、svn)の表示を追加する
function fish_prompt
set -l prompt_symbol '$'
fish_is_root_user; and set prompt_symbol '#'
echo -s (prompt_hostname) \
(set_color blue) (prompt_pwd) \
(set_color yellow) $prompt_symbol (set_color normal)
end
デフォルトのプロンプトを確認する場合は、fish_promptコマンドを実行することにより、表示することができる。
Fishは、継続行のための$PS2は存在しない。
コマンドラインがまだ完了していないことを示すため、行をインデントしたままにしている。
ブロック
FishとBashのブロックの構成を比較する。
# Bash
{
echo Hello
}
# Fish
begin
echo Hello
end
ビルトインおよびその他のコマンド
Fishは、構文よりもビルトインコマンドや外部コマンドに重点を置いている。
使用頻度の高いビルトインコマンドを、以下に示す。
- stringコマンド
- 文字列変換(Bashにおける
${i%foo}等)を行うことができる。 - また、
grepコマンドやsedコマンド等の代わりに使用することができる。
- 文字列変換(Bashにおける
- mathコマンド
- Bashにおける
$((i + 1))の演算を置き換えることができる。 - また、浮動小数点や簡単な関数(三角関数等)も扱うことができる。
- Bashにおける
- argparseコマンド
- 引数をパースすることができる。
- これは、Bashにおける
getoptコマンド、または、Zshにおけるzparseoptsコマンドと同様のコマンドである。
- countコマンド
- 要素数等を数えることができるため、Bashにおける
$#を置き換えることができる。 - またh、
wcコマンドの代わりに使用することができる。
- 要素数等を数えることができるため、Bashにおける
- statusコマンド
- Fishの状態に関する情報(例. 対話型かどうか、現在のリネン番号等)を提供する。
- Bashにおける
$-や$BASH_LINENO等の特殊変数を置き換えることができる。
- seq(1)コマンド
- Bashにおける
{1..10}の範囲拡張の代わりとして使用することができる。 - また、
seqコマンドは別のコマンドに置き換えることができる。
- Bashにおける