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