Posted at

俺、昔cshで頑張ったよ

やっぱりポンコツで使えないな。昔はよく使ったけどbashで十分過ぎるし。

とりあえずcsh/tcshの特徴だけ挙げておこう。


スペースを入れることができる

bourne shell や bash って変数に代入するときキモいよね。

$ a = 1

-bash: a: command not found
$ a=1; echo $a
1

でもcshではスペースを入れても入れなくてもよい。これはbashよりcshのほうがいいね。

$ echo $a

1
$ set a=2
$ echo $a
2


配列のインデックス番号が1から始まる

こういうの止めてほしい。fortranやluaも1オリジン(one-base)だけど、なんか嫌です。

$ csh

$ set arr = (a b c)
$ echo $arr[0]

$ echo $arr[1]
a
$ echo $arr[2]
b
$ echo $arr[3]
c

しかしスライスっぽい使い方ができる。これはtcsh限定の機能かしら。

$ echo $arr[-1]

a
$ echo $arr[-2]
a b
$ echo $arr[-3]
a b c
$ echo $arr[1-2]
a b
$ echo $arr[1-3]
a b c
$ echo $arr[2-3]
b c


関数がない

関数が使えないからgotoで頑張る。頑張らないとダメなのか。aliasで頑張るには限度あるぞ。

#!/bin/csh

switch($#argv)
case 1:
goto _ONE
breaksw
case 2:
goto _TWO
breaksw
default :
goto _EOF
endsw

_ONE:
echo "one"
goto _EOF

_TWO:
echo "two"
goto _EOF

_EOF:
exit(0)


マクロのような書き方ができる

マクロじゃないんだけどね。こういう書き方は許していいのかね。

$ cat kimoi.csh

#!/bin/csh
if ($1 == 1) then
foreach x (a a a)
else
foreach x (b b b)
endif
echo $x
end

$ csh kimoi.csh 1
a
a
a
$ csh kimoi.csh 2
b
b
b


微妙に遅い

計算が遅いのか、イテレータが遅いのか知らんけど、なんか遅い。

$ cat total.csh

#!/bin/tcsh
set total = 0
foreach x (`seq 100000`)
@ total = $total + $x
end
echo $total

$ time tcsh total.csh
5000050000

real 0m2.270s
user 0m1.545s
sys 0m0.721s

bashのほうがだいたい4倍ぐらい速い。

$ cat total.sh

#!/bin/bash
set total = 0
for x in `seq 100000`
do
total=$((total+$x))
done
echo $total

$ time bash total.sh
5000050000

real 0m0.627s
user 0m0.590s
sys 0m0.036s


変数パラメータ展開が微妙に使える

少し使える。bashよりわかりやすい。

$ cat para.csh

#!/bin/csh
set a = "/path/to/cmd"
echo \$a is $a
echo \$a:h is $a:h
echo \$a:t is $a:t

$ csh para.csh
$a is /path/to/cmd
$a:h is /path/to
$a:t is cmd


シグナルトラップが微妙

一応ある。INTとTERMはトラップできるみたい。シグナルハンドラはgotoですか。

$ cat sigtrap.csh

#!/bin/csh
onintr MYTRAP
while(1)
sleep 1
echo -n "."
end

MYTRAP:
echo "trap!"

$ csh sigtrap.csh
...^C
trap!


シェルスクリプト内のawkが書きにくい

bashだと普通にかけるのだが、、、

#!/bin/bash

ls -l |\
awk '{
if ($0 ~/sh$/)
print $NF
}'

cshの場合はawkの構文箇所であっても改行入れる場合はエスケープをしないといけない。なんなの?

#!/bin/csh

ls -l |\
awk '{ \
if ($0 ~/sh$/) \
print hoge, $NF \
}'


謎の変数があったりする

バッククォートでのコマンド実行やパイプ処理でよくわからんステータス判定をする。

コマンド失敗しているけど、builtinの set までは成功しているから、正常と判断するのね。

$ tcsh

$ unset anyerror
$ set a = `sl`
sl: Command not found.
$ echo $?
0

# 変数aは未定義じゃないから成功扱い?かな。
$ echo $?a
1

anyerrorを設定していると、コマンド失敗は失敗としてステータスを返してくれる。 CentOS7のtcshはanyerrorはデフォルト有効になっている。

$ set anyerror

$ set a = `sl`
sl: Command not found.
$ echo $?
1


repeatが使える

これだけはガチに便利。

$ repeat 3 echo "ok"

ok
ok
ok


alloc というbuiltinコマンド

tcshにて使用しているメモリの情報を表示してくれる。おおーと思ったけど、よくよく考えれば、こんなコマンド使う機会ないわ。

$ alloc

tcsh current memory allocation:
Total space allocated from system: 782336
Number of non-inuse chunks: 8
Number of mmapped regions: 0
Total space in mmapped regions: 0
Total allocated space: 670800
Total non-inuse space: 111536
Top-most, releasable space: 70464

# 適当に変数にでかい値を代入しておいて
$ set a = "`find /usr/bin`"
$ set b = "`find /usr/bin`"
$ set c = "`find /usr/bin`"
$ set d = "`find /usr/bin`"
$ set e = "`find /usr/bin`"

# メモリを再確認
$ alloc
tcsh current memory allocation:
Total space allocated from system: 1585152
Number of non-inuse chunks: 288
Number of mmapped regions: 0
Total space in mmapped regions: 0
Total allocated space: 1447760
Total non-inuse space: 137392
Top-most, releasable space: 81584