fishとzsh - プロセス置換などコマンドの書き方の違いあれこれ
普段はfishを使っていて満足だけど、次のようなケースでbash/zshとの違いに戸惑うことがある。
- Web上の記事からコピペで実行したい時
- そういえばfishのコマンドがそのまま載った記事はほとんど見ない気がする
- チーム開発をしていて、他の人がシェアしたコマンドをコピペ実行したい時
- チーム開発をしていて、自分が使ったコマンドを他の人にシェアしたい時
ほとんどの場合エラーメッセージに答えがあるけど一応メモしておく。
以下のコマンド例は注釈がなければfishを指す。
変数定義
zshではAAA=111
と書けるが、fishではset
を使う。
⟩ AAA=111 Unsupported use of '='. In fish, please use 'set AAA 111'. ⟩ set AAA 111 ⟩ echo $AAA 111
参考: set:シェル変数の設定・一覧・消去・確認する6活用
RAILS_ENV=test rails consoleみたいな書き方
コマンド実行時だけ変数定義をしたい時、zshと同じような指定はエラーになる。
⟩ RAILS_ENV=test ./bin/rails c Unsupported use of '='. To run './bin/rails' with a modified environment, please use 'env RAILS_ENV=test ./bin/rails…'
エラーメッセージに書いてある通りenv
を付ける。
⟩ env RAILS_ENV=test ./bin/rails c Running via Spring preloader in process 59475 Loading test environment (Rails 5.0.0.1)
&&や||の書き方
fishとzshの違いで良く見るケース個人的1位。
fishでは&&
や||
をサポートしていない。代わりに;
とand
/or
を使う。
⟩ echo 1 && echo 2 Unsupported use of '&&'. In fish, please use 'COMMAND; and COMMAND'. fish: echo 1 && echo 2 ⟩ echo 1 ;and echo 2 1 2 # orの例 ⟩ cat aa ;or echo 2 cat: aa: No such file or directory 2
ちなみにand
を忘れて;
だけにすると、コマンドが失敗しても継続されるので注意。
# andがないと継続される ⟩ cat a ; echo 2 cat: a: No such file or directory 2 # andがあれば継続されない ⟩ cat a ;and echo 2 cat: a: No such file or directory
終了ステータスのとり方
$?
ではなくて$status
を使う。
⟩ echo $? $? is not the exit status. In fish, please use $status. fish: echo $? ^ ⟩ echo $status 0
$(...) - コマンド置換
コマンドの実行結果を他のコマンドに渡す時の書き方。
⟩ cat $(echo out.txt) $(...) is not supported. In fish, please use '(echo)'. fish: cat $(echo out.txt) ^ ⟩ cat (echo out.txt) this is out
なおfishではバッククォートをサポートしていない。
⟩ cat `echo out.txt` cat: `echo: No such file or directory cat: out.txt`: No such file or directory
<(...) - プロセス置換
例えばディレクトリ内に含まれるファイル一覧の差分を取りたいとき。
/Users/kanno/tmp% tree dir1 dir2 dir1 └── a.txt dir2 └── b.txt
zshでは<()
を使うことで一時ファイルを通すことなく比較できる。
参考: 一時ファイルはもういらない - プロセス置換
# これはzsh /Users/kanno/tmp% diff -u <(ls dir1) <(ls dir2) --- /dev/fd/11 2018-12-15 05:17:56.000000000 +0900 +++ /dev/fd/12 2018-12-15 05:17:56.000000000 +0900 @@ -1 +1 @@ -a.txt +b.txt
普段使わないけど、前職でサーバーに入ってサクッと使っている人がいてカッコいいと思った。
同じことをfishでやるにはpsub
を組み合わせる。
⟩ diff -u (ls dir1 | psub) (ls dir2 | psub) --- /var/folders/n5/z3tch4l11q796wz2m5m_6xd80000gn/T//.psub.eIiVpGBx3M 2018-12-15 05:20:18.000000000 +0900 +++ /var/folders/n5/z3tch4l11q796wz2m5m_6xd80000gn/T//.psub.QhISb6ERoH 2018-12-15 05:20:18.000000000 +0900 @@ -1 +1 @@ -a.txt +b.txt
リダイレクトの書き方
標準エラー出力は^
を使う。追記する場合は^^
。
⟩ cat aaa ^out.txt ⟩ cat out.txt cat: aaa: No such file or directory
存在しないファイルを上書きしないようにするには>?
や^?
を使う。
⟩ echo aa >? out.txt The file 'out.txt' already exists
標準出力と標準エラー出力を同時に出すにはこう書く。
⟩ echo aa > out.txt ^&1
絶対忘れるが、bash/zshの2>&1
も毎回ググっているので問題ない^^
ワイルドカードの解釈
**/*.php
のような指定をすると、zshと違いカレントディレクトリは対象外になる。
カレントディレクトリも対象とするには***.php
とする。
⟩ ls **/*.php php/empty.php ⟩ ls ***.php algo.php php/empty.php