Diff of UNIX/コマンド/シェル・シェル組み込み/zsh


TITLE:zsh - 良いとこ取りをしたシェル
#navi(UNIX/コマンド)
#contentsx

*紹介 [#zaeedfcb]

zsh は bash や tcsh や ksh の良いとこ取りをしたシェルです。
他のすべてのシェルの機能を持つことから最後のシェルという意味で zsh と名付けられたそうです。
csh 系ではなく sh 系に属すので、会津大生は引っ越ししにくいかもしれません。

とりあえず google で検索すると、
[[Introduction of the ZSH>http://www.gentei.org/~yuuji/rec/pc/intro-zsh.html]] や
[[Z-Shell FAQ (Japanese)>http://dengaku.org/~naoki/zsh/FAQ-J/zshfaq-j.html]] (若松さん@元会津大生和訳) 
のページなどその他多数でてきます。

*bash(sh系)からの乗り換え方法 [#i3804f6c]

zshは/bin/zshにインストールされていますが
会津大学では /etc/shellsに/bin/zshのエントリが無いのでpasswd -sでは変更できません。
他のシステムでもログインシェルを zsh に変更できないことは多いです。
このような場合は、~/.profileに

 [ -f /bin/zsh ] && SHELL=/bin/zsh
 [ -f /bin/zsh ] && exec /bin/zsh -l

と書いておくことで実質的にログインシェルとして利用できます。
場所はファイル内の適当な所で構いません。

設定ファイルは[[.zshrc]]や[[.zshenv]]を参考にしてください。(ログインシェルではないために .zprofile や .zlogin 等は使えません)

RIGHT:written by s1080134.
*zshのアップデート [#v3498625]
(2010年01月14の時点で)会津大学の標準でzshのバージョンは4.2.1ですが、4.3.10も使えます。
[[zsh.org>http://www.zsh.org/]]から、zsh 4.3.3 と zsh 4.3.10をダウンロードします。
4.3.3はoldの中にあります。
.tar.bz2と.tar.gzがありますが、中身は同じものです。
4.2.1から4.3.10にしようとすると、途中で

 checking if tcsetpgrp() actually works... error~
 configure: error: unexpected return status

となってしまいますのでこの様な形にしました。
まず、4.3.3をインストールします。
 ./configure --enable-multibyte --prefix=
とすることを忘れないでください。
configure後 は make と make install を実行します。
$HOME/bin/zsh-4.3.3/ にインストールした場合は、$HOME/bin/zsh-4.3.3/bin/zsh を実行してください。
次に上と同じ様な手順で4.3.10をインストールします。
4.3.10 を導入後は 4.3.3 を make uninstall します。~
(以下は zsh 4.3.10 での説明です)

*zsh の文法 [#abf8c6b1]
**変数 [#e685baea]
***変数名 [#f65bd0c8]
アルファベットの大文字・小文字、数字、_ が使えますが、数字は 1 文字目には使用できません。
大文字小文字は区別されます。~
zshでは、組み込み変数(シェルの動作時に使われます)は大文字と小文字で対になっています。小文字では配列を表します。[[.zshenv]]では、pathがその一例として取り上げられています。
***代入、出力 [#lc02628d]
代入は 変数名=値 とします。スペースを含めません。$ をつけることにより、値の参照ができます。~
以下は代入と出力の例です。

 % hello="Hello, "
 % echo $hello
 Hello, 
 % world="World\!"
 % echo $hello$world
 Hello, World!
 % printf "%s\n" $hello
 Hello, 
 % print $world
 World!
 % echo "$hello"
 Hello, 
 % echo '$world\n'
 $world
 
 % echo -n "$hello\n"
 Hello, 
 %

***変数の削除 [#he94b27e]
上の例で、変数helloを削除する場合は、以下のようにします。

 % unset hello
 % echo $hello
 
 %

***シェル変数 [#j5dc7232]
親シェルのシェル変数は、サブシェルでは参照できません(ALL_EXPORT オプションが有効になっていると、変数は環境変数となります)。
 
 % hello=Hello
 % echo $hello
 Hello
 % zsh
 % echo $hello
 
 % hello="sub Hello"
 % echo $hello
 sub Hello
 % exit
 % echo $hello
 Hello
 %

set コマンドを使うと、変数の一覧が出力されます。

***環境変数 [#z820711d]
環境変数は、サブシェルやサブプロセスに値がコピーされます。

 % export shell_env="shell env val"
 % echo $shell_env
 shell env val
 % zsh
 % echo $shell_env
 shell env val
 % unset shell_env
 % echo $shell_env
 
 % exit
 % echo $shell_env
 shell env val

printenv コマンドを使うと、環境変数の一覧が出力されます。

***配列 [#zc9984c8]
.zshenv の組み込み変数 path は、配列が使われています。配列の作成は以下のようにします。~
注意することは、zsh の配列の添え字は 1 から始まることです。

 % arr=(aa "bb" 22 "44")
 % echo $arr[1]
 aa
 % echo $((arr[4]*2))
 88
 % echo $#arr
 4
 $ echo $arr[*]
 aa bb 22 44
 % echo $arr[2,4]
 bb 22 44
 $ echo $arr[-2]
 22
 $ echo $arr[-2,4]
 22 44
 $ echo $arr[$#arr]
 44

**算術計算 [#k8779539]
zsh で使用可能な演算子は以下の通りです。

 + 、- 、* 、/ 、% (剰余)、++ (インクリメント)、-- (デクリメント)、** (冪乗)
 & (ビット単位の論理積)、| (ビット単位の論理和)、~ (ビット単位の論理否定)、^ (ビット単位の排他的論理和)
 ! (論理否定)、, (連続評価)、&& (論理積)、|| (論理和)
 < 、> 、<= 、>= 、!=、==

 % echo $((11))
 11
 % echo $((11!=3))
 1
 % echo $((11==3))
 0
 % n=5; echo $((n))
 5
 % 

さらに、mathfunc モジュールは zsh の算術計算をより高機能にします。

 % zmodload zsh/mathfunc
 % echo $((1/2))
 0
 % echo $((1/2.0))
 0.5
 % printf "%.3f\n" $((1/3.0))
 0.333
 % printf "%.9f\n" $(( 4*atan(1) ))
 3.141592654
 % printf "%.9f\n" $(( log1p(1) ))
 0.693147181

詳細は run-help zshmodules の zsh/mathfunc を参考にしてください。 

**ヒストリ [#h9257d86]


**シェルスクリプト [#v8079fe4]
注意:ここに掲載する構文は run-help コマンドで確認できる構文と同等です。
***break, continue [#pe46cbad]
***case [#w3d65870]
***for [#r17e4d86]
zsh の for 文には、大きく分けて 2 通りの書き方があります。~
1) foreach のような for 文~
構文:

 for name ... [ in word ... ] term do list done

name が複数あると、name 分の word が代入されます。以下の例を参照。

 % for i j in {1..7} ; do ;
 for% echo $i $j
 for% ; done
 1 2
 3 4
 5 6
 7

word は上の例のように {1..7} でもよいし、ファイル名でもよいし、{A-z}のような展開でもよい(setopt brace_ccl が必要)です。~
word がなければ、for 文は実行されません。

 % ls 
 tes1 tes2 tes3
 % for file in * ; do ;
 for% echo $file
 for% ; done
 tes1
 tes2
 tes3
 % for i; do ;
 for% echo 1 2 3 4
 for% ; done
 %

term は上例で、; となっていますが、; のかわりに改行でもよいです。

 % for file in *
 for% do
 for% echo $file
 for% done
 tes1
 tes2
 tes3
 
2) JAVA や C言語等で見られる for 文~
構文:

 for (( [expr1] ; [expr2] ; [expr3] )) do list done

これは JAVA 等と同じなので例のみ挙げておきます。

 % for ((i = 0; i < 5; i++)); do ;
 for% echo $i
 for% ;done 
 0
 1
 2
 3
 4

***if, then, elif, else [#t71a023e]

構文: (説明のために意図的に list に番号を振った)

 if list_1 then list_2 [ elif list_3 then list_4 ] ... [ else list_n ] fi

zsh の if 文は、やや複雑な部分があります。
list_2 が実行されるのは、list_1 が正である、%%%または list_1 が 0 の終了ステータス(=正常に終了)を返す場合%%%に実行されます(詳細は後述)。
list_2 が実行されるのは、list_1 が true である、%%%または list_1 が 0 の終了ステータス(=正常に終了)を返す場合%%%に実行されます(詳細は後述)。
この if 文のには、2つの書き方があるので、以下に番号で分岐しておきます。
例として使われているのは、[[select>#t6d9aa44]] の例中にある if 文です。

1) [ EXP ] を使う場合~
まず1つ目は [ ] を使う場合です。この場合、プログラミング中によく使う数値の比較 <= や < 等 (OP) が使用できません。~

 % n=4
 % if [ $n < 4 ] ; then ;
 then% echo $n
 then% ; fi
 zsh: no such file or directory: 4

となってしまうからです。この場合、使用する OP は -lt です。

 % n=1
 % if [ $n -lt 4 ] ; then ;
 then% echo $n
 then% ; fi
 1

OP については、ここにはリストアップしません。ここに書くとずらずらとなってしまって見にくくなるからです。ただし、zsh の補完機能によってターミナル上で逐一確認できますので、そちらを参考にすると良いでしょう。~
条件を AND/OR 結合する方法です。 AND には -a, OR には -o が使われます。

 % mkdir testdir && cd !!:$
 % touch file1 file2 && ls
 . .. file1 file2
 % if [ -e file1 -a -e file2 ] ; then ;
 then% echo "true\n"
 then% ; else ;
 else% echo "false\n"
 else% ; fi
 true
 
 % if [ -e file1 -o -e file3 ] ; then ;
 then% echo "true\n"
 then% ; else ;
 else% echo "false\n"
 else% ; fi
 true
 
 % if [ -e file1 -a -e file3 ] ; then ;
 then% echo "true\n"
 then% ; else ;
 else% echo "false\n"
 else% ; fi
 false
 
 % if [ -e file1 -a ! -e file3 ] ; then ;
 then% echo "true\n"
 then% ; else ;
 else% echo "false\n"
 else% ; fi
 false
 
上のスクリプトは、file1 と file2/file3 の有無 (-e を使う) によって改行を含んだ true もしくは false を出力します。
! で true と false の入れ替えができます。

2) [[ EXP ]] を使う場合

[ EXP ] の場合と大きな違いがありませんが、AND/OR 結合や数値比較での違いがあります。~
bash では使用可能ですが、''bsh では使用できません''。以下に zsh と sh とでの例を示します。

 % zsh
 % n=2
 % if [[ $n < 4 ]] ; then ;
 then% echo $n
 then% ; fi
 2
 % if [[ $n -lt 4 ]] ; then ;
 then% echo $n
 then% ; fi
 2
 % if [[ -e file1 && -e file2 ]] ; then ;
 then% echo "true\n"
 then% ; else ;
 else% echo "false\n"
 else% ; fi
 true
 
 % if [[ -e file1 || -e file3 ]] ; then ;
 then% echo "true\n"
 then% ; else ;
 else% echo "false\n"
 else% ; fi
 true
 
 % sh
 $ n=2
 $ if [[ $number -le 4 ]] ; then
 > echo $n
 > fi
 sh: [[: not found
 $ if [ $number -le 4 ] ; then
 > echo $n
 > fi
 2

ここで後述としておいた、終了ステータスを使った if 文についてです。~
if 文の条件部分に書くのは文です。従って、文である if then fi も条件部分に書けます。
以下のファイルを genExit.sh として用意します。

 #!/bin/zsh
 
 setopt prompt_subst
 
 if [[ $((RANDOM%2)) == 0 ]] ; then ;
   exit 0
 ; else ;
   exit 1
 ; fi

次にこのファイルを使って if 文を書きます。

 % n=4
 % repeat 10; do ;
 repeat% if
 repeat if% if [[ $n -le 4 ]] ; then ;
 repeat if then% ./genExit.sh
 repeat if% ; fi
 repeat if% ; then ;
 repeat then% echo "exit 0"
 repeat then% ; else ;
 repeat else% echo "exit 1"
 repeat else% ; fi
 repeat ; done
 exit 0
 exit 1
 exit 1
 exit 0
 exit 1
 exit 0
 exit 0
 exit 0
 exit 1
 exit 0

repeat コマンドについては、[[repeat>#pb9cc837]] を参照してください。~
genExit.sh の終了ステータスがどちらであるかが出力されているだけです。ネストがたくさんあって見にくいように見えますが、左プロンプトがその解決に役立ちます。
***read [#l33c2600]
***repeat [#pb9cc837]
構文:

 repeat word do list done

word には整数値を記入します。list を word 回実行するときに使います。(以下の例は zsh の本を参考にした)

 % repeat 10; do;
 repeat% echo -n "`date`\r"
 repeat% sleep 1
 repeat% ; done

***select [#t6d9aa44]
構文:

 select name [ in word ... term ] do list done

word の中から 1 つ選択して name に代入します。

 % select number in {1..5} ; do ;
 select% if [[ 1 -le $number && $number -le 5]] ; then ;
 select then% echo $number
 select then% ; else ;
 select else% echo "無効な選択です"
 select else% ; fi ;
 select% done
 1) 1  2) 2  3) 3  4) 4  5) 5
 ?# 1
 1
 ?# 6
 無効な選択です
***sleep [#v596994b]
構文:

 sleep [number[smhd]...]

number で指定された間の遅延です。s は秒、m は分、 h は時間、d は日です。特に指定しない場合は秒になります。バックグラウンドでも動作します。そのとき、フォアグラウンドになったとき、遅延する時間が経過していなければ、フォアグラウンドで残りの遅延をします。

 % for i {1..100}; do ;
 for% echo -n '\a'
 for% sleep $((60/100.0))
 for% ; done
***until [#ia58c7f8]
***while [#yfa43d9b]
構文:

 while list do list done

list が 0 で終了するまで繰り返します。

***引数, shift [#zc715505]
***特殊な繰り返し [#ae83c3d1]
1) for 文の代替
 % echo {1..4}
 1 2 3 4

2) yes コマンド~
構文:
 yes [string...]

yes コマンドは kill されるまで表示し続けます。引数が与えられないと、y に 改行を付加したものを出力し続けます。

 % yes e
 e
 e
 e^C

***左プロンプト [#f8b77d83]
zsh では、現在どのスコープなのかが左プロンプトでわかります。

 % for i in {1..9} ; do ;
 for% if [[ $((i%2)) == 0 ]] ; then;
 for then% echo $i
 for then% ; fi
 for% ; done
 2
 4
 6
 8
*高機能なリダイレクト [#l1ea6272]

 % <file1 >file2

file1 を file2 にコピーする時に使います。
テキストファイルだけではなく、画像ファイル等にも有効です。~
zshでは、複数の指定が可能で、

 % <file1 <file2 >file3 >file4 >file5

とすることによって、file1 と file2 の両方の内容が file3 と file4 と file5に書き込まれます。

*zsh を使うにあたって知っておくと便利なコマンドまたは知識 [#kfdad3cd]

[<tab>] は TAB キーを押すことを意味します。~
% ESC-X はターミナル上で ESC キーと X キーを同時に押すことを意味します。

**autoload [#ob668bd2]
関数定義がされているときに、ログイン時にその定義を読み込むのではなく、実行時に読み込みをします。

 % autoload -U compinit
 % compinit

zsh にはその要となる compsys という補完機能がありますが、その機能を有効にする方法です。初めてこのコマンドを実行すると少し時間がかかりますが、ホームディレクトリに補完の収集結果として .zcompdump を作成して次回実行された時はそのファイルを読み込むので、2回目以降はそれほど時間がかからなくなります。

 % autolaod -U tetris
 % zle -N tetirs
 % ESC-x 
 execute: tetirs

これは tetris ウィジェットを読み込むときに使います。疲れた時にやるといいと思います。~
以下は autoload のオプション一覧です。

 -U エイリアス展開をしません。
 -X 関数名を指定せずに関数の中で使われます。関数の定義を同じ名前のオートロードの関数で上書きします。
 +X 指定された関数が未定義の時にのみ読み込みます。unfunction コマンドとともに使われることがあります。
 -k ksh 風の autoload です。
 -t デバッグ時のトレース。
 -w 関数がすでにコンパイル済みの時に使います。
 -z zsh 風の autolaod です。

**cd(chdir) [#n019f568]
csh等とは違った使い方ができます(cd を打たなくてもディレクトリ移動が可能です)。windowsのexplorerの戻るの機能に似ています。

 % ~/dir1/dir2/bin
 % ~root/bin
 % /
 
このあとで、cd -[<tab>] で

 Completing directory stack
 0 -- /home/student/sxxxxxxx/dir1/dir2/bin
 1 -- /root/bin
 2 -- /

という補完の一覧がでます。cd -1 とすると、/root/bin に移動できます。cd +[<tab>] では、表示される順番が逆になります。
**disown [#s45028fa]
ジョブテーブルからジョブを削除します。詳細は jobs コマンドを参照してください。~
オプションはありません。

**info [#c9964da2]
たとえばinfo s[<tab>] で一覧表示すると、

 size     -- List section sizes and total size.
 spline   -- Interpolate between points in datasets.
 strings  -- List printable strings from files.
 strip    -- Discard symbols.

という一覧表示になります

**jobs [#he5054e2]
zsh から exit コマンドを使ってシェルから抜けようとすると、

 zsh: you have running jobs.

とターミナル上に表示されることがあります。これは & で実行したジョブで終了されていないのがまだ残っていることを示しています。そのまま exit コマンドを繰り返すと

 zsh: warning: X jobs SIGHUPed

という警告が出ます(X には実際には数値が書かれています)。これを防ぐために jobs コマンドを使います。

 % gedit &
 % thunderbird &
 % firefox &
 % file-roller &|
 % acroread &!
 % jobs
 [1]    running    gedit
 [2]  - running    tunderbird
 [3]  + running    firefox

のようになります。running の前に書かれている - や + は、- は直前のジョブ、 + は現在のジョブであることを示しています。~
5つのジョブを実行していますが、後半の2つは &! または &| で起動しています。これは zsh のジョブテーブルに入れずに起動するという意味です。言い換えると、zsh から抜けても終了されずに起動され続けることを意味しています。~
これは disown コマンドと同様です。

 % jobs
 [1]    running    gedit
 [2]  - running    tunderbird
 [3]  + running    firefox
 % disown %firefox
 % jobs
 [1]  - running    gedit
 [2]  + running    tunderbird
 % disown %[<tab>]
 Completing job
 %1  -- gedit
 %2  -- thunderbird

となります。なにも指定せずに disown を実行すると、現在のジョブ(+)が削除されます。disown コマンドの代わりに直接ジョブを指定する方法もあります。

 % %thunderbird &!
 % %1 &|
 % jobs
 %

jobs のオプション一覧です。

 -d ジョブを起動したときのディレクトリの出力
 -l プロセス ID の出力
 -p プロセスグループのプロセス ID を出力
 -r running のジョブのみの出力
 -s stopped のジョブのみ

**run-help [#h1e9dfd5]
man コマンドと同じ機能を持ちますが、ターミナル上ではこちらの方が便利なことがあります。~
例) [[whatis]] コマンドが何かわからない場合

 % whatis ESC-h
 whatis is /usr/bin/whatis
 
 ...(マニュアルの内容)...
 
 % whatis

まずは1行目です。whatis の後に続けて ESC-h を入力します。このとき、[[run-help]] whatis に自動的に置き換わって実行されます。その次の行では [[which]] whatis 相当のコマンドが実行されていますが実際に見るのはマニュアルを見た後でしょう。~
最後の行です。自動的に whatis が入力されていてコマンドの後から続けて作業ができます。 ~
**zcompile [#q93c16cd]
zsh のスクリプトをコンパイルします。コンパイルすると実行速度が速くなります。~
.zshrc や .zlogin 等もコンパイルできますが、それらを編集したあとは zcompile しないと変更が有効になりません。ファイル名の後に .zwc がついたファイルが生成されます。
**zle [#w093be9a]
**zmodload [#afeaae6c]

**グロブパターン [#l57d1197]
ls -l .z* のように絞り込んでリストを出力する場合、zsh ではファイル名の他にファイル属性でも絞り込みが可能です。
 % ls -l
 drwxr-xr-x  3 s1170232 student 4.0K Feb  9 22:28 .
 drwxr-xr-x 68 s1170232 student 8.0K Feb  9 22:34 ..
 drwxr-xr-x  2 s1170232 student 4.0K Feb  9 22:26 dir1
 -r--------  1 s1170232 student    0 Feb  9 22:25 file1
 --w-------  1 s1170232 student    0 Feb  9 22:25 file2
 ---s------  1 s1170232 student    0 Feb  9 22:25 file3
 -rwx------  1 s1170232 student    0 Feb  9 22:25 file4
 lrwxrwxrwx  1 s1170232 student   22 Feb  9 22:28 link1 -> /home/student/s1170232
 % ls -l {file*,link1}(f/u+r/,@)
 -r-------- 1 s1170232 student  0 Feb  9 22:25 file1
 -rwx------ 1 s1170232 student  0 Feb  9 22:25 file4
 lrwxrwxrwx 1 s1170232 student 22 Feb  9 22:28 link1 -> /home/student/s1170232
 % rm {file*,link1}(r,s)
 % $ ls -l
 drwxr-xr-x  3 s1170232 student 4.0K Feb  9 22:51 .
 drwxr-xr-x 68 s1170232 student 8.0K Feb  9 22:51 ..
 drwxr-xr-x  2 s1170232 student 4.0K Feb  9 22:26 dir1
 --w-------  1 s1170232 student    0 Feb  9 22:25 file2

以下は主な修飾子の一覧です。
 (/) ディレクトリである
 (.) 通常ファイルである
 (@) シンボリックリンクである
 (*) 実行ファイルである
 (r) 属性に u+r がある
 (w) 属性に u+w がある
 (x) 属性に u+x がある
 (A) 属性に g+r がある
 (I) 属性に g+w がある
 (E) 属性に g+x がある
 (R) 属性に o+r がある
 (W) 属性に o+w がある
 (X) 属性に o+x がある
 (s) SetUID ビットが与えられている 
 (S) SetGID ビットが与えられている
 (t) Sticky ビットが与えられている
 (f) 8進数とともに用いられる場合、f に続けて =、+、-、?を使います。
     = では、指定された属性に一致するもの、+ はその属性があるもの、 
     - ではその属性がないもの、? はどの権限でもよい(例: (f+1?5))。
     = のみ省略可能です(例: (f100))。
     u+r 等で使われる場合、//内に書きます(例: (f/u+r,o-x/))。
 (a-X) アクセス日時が X 日前より後である
       a と -X の間に、s をつけると X 秒、m をつけると X 分、h をつけると X 時間、
       w をつけると X 週間、M をつけると X ヶ月になります。
 (a+X) アクセス日時が X 日前より過去である
       a と +X の間には、-X の時と同じ文字が指定できる。
 (m-X) 修正日時が X 日前より後である
       a と同様、+X もある。 
 (L-X) X バイト未満のファイル
       L と -X の間に k をつけるとキロバイト、m をつけるとメガバイトになります。
 (L+X) X バイトより大きいファイル
 
 ◆ ^ に続いた修飾子は意味が反対になります。また、ターミナル上で a などと打つと
      補完の一覧が出てくるので、そこでも確認しつつ入力が可能です。

この修飾子には AND 結合と OR 結合があり、(*L+X)などとすれば AND、(*,L+X)などとすれば OR になります。
この修飾子を使うと、以下のようなファイル検索ができます。

 % ./**/*(.{Lm+10,aM+1})

これは、カレントディレクトリより深い階層にある通常ファイルで、10MB よりも大きいか 1 ヶ月間のアクセスがないファイルを検索しています。

#navi(UNIX/コマンド,,footer)
xrea