2001/5/16
リダイレクションの指定は順番によって違う。 次の2つはどうちがうのか?
$ ls >file 2>&1 $ ls 2>&1 >file
リダイレクションの有効範囲はパイプの中だけ。
$ ls /var/spool/cron 2>&1 | cat -n $ ls /var/spool/cron | cat -n 2>&1
シェルスクリプトは B shell (sh) でかく。実行方法には 2とおりある。
シェルスクリプトは基本的にコマンド列。実行する順にだらだら書けばよい。
ls -l; cat hoge echo ore wa ore;1行1コマンド。 1行に複数のコマンドを入れる場合は ; が必要。
シェルはプログラミング言語なので、変数も条件分岐もループもできる。
#!/bin/sh if ls hogehoge; then echo "hogehoge はあるよ"; else echo "hogehoge はないよ"; fi
test は 条件式によって終了状態を変える。これを 使うと、if でもっと複雑な条件かける :
スクリプト lessdir:
#!/bin/sh if test -d $1; then ls $1; else less $1; fi$1, $2, $3 ... には、シェルスクリプトを実行したときの コマンド引数が入る。
#!/bin/sh if [ -d $1 ]; then ls $1; else less $1; fiでも、ls | grep abc | lessdir とかが動くようになってほしい :
#!/bin/sh if [ ! "$1" ]; then less; # 引数が省略された場合 elif [ -d $1 ]; then ls -F $1; # 引数があって、それがディレクトリだった場合 else less; # 引数があって、それがファイルだった場合 fi
問: なぜ 最初の $1 には "" をつけるが必要あるか?
# はシェルではコメントとみなされる。だから最初の一行は無視される。
さらに、exec を使うと、生成されるプロセスが増えなくてすむ。
#!/bin/sh if [ ! "$1" ]; then exec less elif [ -d $1 ]; then exec ls -F $1 else exec less fi
問: このスクリプトにはバグがある。どこか。
for をつかうと、複数の word に対してなにかできる。
for i in *; do echo "Rename: $i" mv $i $i.2 doneさらに、` ` を使うと、コマンドの出力を word列として とり出せる (改行は除かれる)。
for i in `cat filelist`; do echo "Rename: $i" mv $i $i.2 doneシェル変数は
i=1 hoge=agagagとかやる。=の前後にスペースあけないこと。 コマンドとみなされるぞ!
シェルで計算するには expr を ` ` で使えば OK。 exprはじつはシェルのコマンドではない。シェルは計算も一人ではできない。
i=1 while [ $i -le 10 ]; do echo $i i=`expr $i + 1` # expr の引数は開けること! done一行でもかけるよ。
i=1;while [ $i -le 10 ];do echo $i;i=`expr $i + 1`;done
スペースに注意せよ! 開けないと引数とみなしてくれない。
例 : if [ $x = 10 ] then echo $x;exit(○) if[$x = 10] then echo$x; exit(×)また、シェル変数を使うときの = は前後を開けてはならない。
例 : x="abc" (○) x = abc (×)
シェルスクリプトでよく使うコマンド (内部コマンドも外部コマンドもある)
例: [ "$1" = 234 ]
[ \( "$a" eq "hoge" \) -o \( "$a" eq "moge" \) ]
[ -f "$f" ]
if コマンド; then コマンド; fi
if コマンド; then コマンド1; else コマンド2; fi
if コマンド; then コマンド1; elif コマンド2; then ...
例: `expr 2 * 3 + $a`
case もの in
パターン1) コマンド1; .. ;;
パターン2) コマンド2; .. ;;
esac
シェルスクリプトでパターンにマッチさせたいときはこれを使うしかない。
while コマンド; do コマンド1; .. ; done
知っていると便利なテキスト処理コマンド (斜体 は引数。[ ] 内は省略可能)。
このほかに知っていて損はないもの。
問: find -name *.txt は間違い。なぜか?
また、以下のアクションが指定可能。
問: find . -exec ls ; は間違い。なぜか?
各コマンドの詳細はmanすること。
#!/bin/sh
# lpo:
# -P printer : speficy printer
# -m : speficy twocolumns
# -1 : onecolumn
# -p : onecolumn, portlait-duplex
# -2 : twocolumn, landscape-duplex
set -- `getopt P:K:Rtm1d2 $*`
if [ $? != 0 ]; then
echo "usage: lpo [-Pprinter] [-m1d2] [file ...]"
fi
p=pst
m=0
a=-np
c=1
t=0
r=0
while [ $1 != -- ]; do
case $1 in
-P) shift; p=$1;;
-K) shift; c=$1;;
-R) r=1;;
-t) t=1;;
-m) m=1;;
-1) m=0; a=-p; p=ps;;
-p) m=0; a=-p; p=psdp;;
-2) m=1; p=psdl;;
esac
shift;
done
shift;
spool() {
if [ $m = 1 ]; then
psmulti -nodecor $* | lpr -P$p -K$c;
else
lpr -P$p -K$c $*;
fi
}
if [ $# = 0 ]; then
if [ $t = 1 ]; then
a2ps $a | spool; exit;
else
spool; exit;
fi
fi
for i in $*; do
case $i in
*.ps)
spool $i;;
*.ps.gz)
gzip -dc $i | spool;;
*.pdf)
tmp=/tmp/prt.$$
acroread -toPostScript -size a4 -shrink -pairs $i $tmp
spool $tmp
rm $tmp;;
*.dvi)
/usr/local/bin/dvips -f $i | spool;;
*.gif)
giftopnm $i | pnmtops | spool;;
*)
if [ $r = 1 ]; then spool $i; exit; fi
if [ "X$a" = "X-np" ]; then m=0; fi
a2ps $a $i | spool;;
esac
done