% touch toto toto という file を作ります。 % ls -l toto 大きさは 0 byte です。 -rw-r--r-- 1 rsaito bin 0 Jul 7 21:24 toto % set noclobber noclobber を set します。 % ls -l > toto エラーメッセージがでます。 toto: File exists. % unset noclobber noclobber を解除 unset します。 % ls -l > toto 今度は エラーがでなくなりました。 %一度に多くの人が同時にコマンドを使う可能性は unix の場合あり ます。プログラムで 同じfile 名に出力すると、同時に動いた場合 正しく動かない場合があります。それを避けるために $$ を使いま す。
#!/bin/tcsh # 7.1 file への出力 ls -l >! toto.$$ ls -l toto.$$ cat toto.$$
#!/bin/tcsh # 7.2 lock file をもちいた制御 lock # # /tmp/a.lock がある限り、while ... end の間を繰り返す。 while ( -e /tmp/a.lock ) # 2 秒待ちます。 sleep 2 end # もし a.lockock が無ければ、作業をする前に file を作る touch /tmp/a.lock # 誤動作があっても誰でも消すことができるようにします。 chmod 777 /tmp/a.lock # ここから 実際の作業 echo "作業を始めます。10 秒お休みです。" sleep 10 echo "作業を終ります。" # 最後に lock file を忘れずに消します。 rm /tmp/a.lock
待ち行列の最後に追加するのは >> で簡単ですが、csh では 1 行 づつ file から読んで処理することができません。(少なくても私 は知りません。) そこで、start から end まで切り出すようなこ とを awk や sed で 行います。(前のところを みてください。) 一行読むのに便利なコマンドは perl の <> コマンドです。興味の あるひとは perl 入門を見てください。でも多くの場合には、1 行 づつ読んで処理することはあまり必要ありません。
プログラムは、(1) 自動処理をする sewanin2 と (2) 自動返信を する replymail2 からなります。sewanin2 から replymail2 を読ん でいます。replymail2 を呼ぶ場合には、送られた e-mail を解読 して 環境変数として、REPLY(返送先), SENDER (送り主)、FROM (誰から) の 3 つの変数から、BACK (自動返送先) を選択してい ます。replaymail2 を単独で使う場合には、この $BACK を setenv で replaymail2 の中で設定する必要があります。
さらに sewanin2 の中で、getitem (項目を取り出す)、getright (項目の右部分を取り出す) プログラムを読んでいます。これらも 紹介しましょう。プログラムを分解すると、デバッグがしやすいで す。欠点は変数を受け継がせるために、環境変数の設定が必要です。
また e-mail を sewanin2 に読ませるには、~/.foward という file をつくってそこに
"| ~/bin/sewanin2"
のような設定が必要です。この場合普通の e-mail もこれに処理去 れてしまいますので、分けたい場合にはさらに工夫が必要です。 通常は、自動処理専用の e-mail address を持つ方が簡単です。
以下はスクリプトの中で説明します。初心者の人はこの先を見なく ても ok です。実際に動かすには、沢山の file を用意しなければ いけません。これを自動的に作る script も実際には用意されてい ます。ですが、こんなに複雑に設定しなくても、一部分を利用する ことは可能ですので、あきらめず読んでみてください。
#!/bin/tcsh # # メールの自動管理プログラム。 # ver. 1.00 by Ryouma Matsuo. 97/12/19 # 1.01 by R. Saito 97/12/20 # AR は処理する プログラムがはいっている場所です。 set AR = "/local2/auto-reply" # 処理に必要な path を設定しています。 set path =(. $AR /usr/ucb /bin /usr/bin /usr/local/bin ) # 作られる file の属性は 777 にします。 umask 000 # 作業 directory に移動します。 cd $AR # sewanin.lock がある間は処理しません。 while ( -e /tmp/sewanin.lock ) sleep 2 end # sewanin.lock がなければ作業開始です。 touch /tmp/sewanin.lock chmod 777 /tmp/sewanin.lock # 初期化をします。 # 途中で C-c がかかった場合には、作業 file を消去する END に # いきます。 onintr END # 作業 file の設定です。 set tmpf=/tmp/oshigoto$$.tmp1 set tmpf2=/tmp/oshigoto$$.tmp2 set DATE=`date` # ここで まず e-mail の中身が全て $tmpf にはいります。 nkf -e >! $tmpf # 次に start と end と書いた部分を切り出します。tmpf2 に書き # 出します。ここの間にあるものだけを処理します。 awk /start/,/end/ < $tmpf > $tmpf2 #sed -n '/^start/,/^end/p' $tmpf > $tmpf2 # 返送先の読みだしを $tmpf から行います。検索文字(Reply-to:) を探してい # ます。大文字小文字を区別しません。結果を環境変数にいれます。 setenv REPLY `sed -n 's/^[Rr][Ee][Pp][Ll][Yy]-[Tt][Oo]: \(.*\)$/\1/p'` < $tmpf setenv SENDER `sed -n 's/^[Ss][Ee][Nn][Dd][Ee][Rr]: \(.*\)$/\1/p'` < $tmpf setenv FROM `sed -n 's/^[Ff][Rr][Oo][Mm]: \(.*\)$/\1/p'` < $tmpf # ここで優先順位をつけて返送先を選択します。 setenv BACK2 $REPLY if ( "$BACK2" == "" ) setenv BACK2 "$FROM" if ( "$BACK2" == "" ) setenv BACK2 "$SENDER" if ( "$BACK2" == "" ) goto END # 最終的な返送先として BACK を選択します。 setenv BACK `echo $BACK2 | sed 's/^.*<\(.*\)>.*$/\1/' | awk -F' ' '{print $1}'` # echo $BACK # 送られて来る手紙は以下のような構成になっているものとします。 # 用件(jobname)をお仕事名として、 # 登録したお仕事のみ処理をするようにします # また項目は、処理する側から書式として設定したものです。 # 項目については下に説明があります。 # start # jobname お仕事名 # 項目1 項目1の中身 # 項目2 項目2の中身 # ....... # end # # まずはお仕事名の取り出しです。 setenv JOBNAME `awk -F' ' '$1 ~ /[Jj][Oo][Bb][Nn][Aa][Mm][Ee]/ {print $2;exit}' $tmpf2` # お仕事名が無い場合には、no-jobname という message が # かかれた No-JOB.mes という file を送り返します。 if ( "$JOBNAME" == "") then # 念のため 切り出した部分 ($tmpf2) もつけます。 replymail2 $AR/Messages/No-JOB.mes $tmpf2 goto END endif # # 以下お仕事名のある空間 $AR/job/$JOBNAME にいって、お仕事をします。 # job 以下の directory と file を作ります。$JOBNAME という # directory にいって作業をします。 # # お仕事の仕様は $JOBNAME.job にかかれています。 # if (-e job/$JOBNAME/$JOBNAME.job) then cd job/$JOBNAME else # お仕事名が登録されていない場合です。 # Bad-JOB.mes という message を返します。 # 念のため 切り出した部分 ($tmpf2) もつけます。 replymail2 $AR/Messages/Bad-JOB.mes $tmpf2 goto END endif # お仕事の仕様 (1) です。 # もし $AR/job/$JOBNAME/$JOBNAME.job に # userlist: YES # と 1行かかれていたら、job/$JOBNAME/$JOBNAME.lst という file が # 必ず無ければいけません。ここに受け取ることができる user の # e-mail を 記入していれば、その人からしか処理しません。 # set USERLIST=`awk -F' ' '$1 ~ /[Uu][Ss][Ee][Rr][Ll][Ii][Ss][Tt]:/ {print $2;exit}' < $JOBNAME.job` if ( "$USERLIST" == "YES" ) then set EXIST=`grep -i $BACK $JOBNAME.lst` if ( "$EXIST" == "" ) then # もし 返送者 $BACK がリストになければ、No-User.mes と # 切り出したところ ($tmpf2) をつけてお返事します。 replymail2 $AR/Messages/No-User.mes $tmpf2 goto END endif endif # # さて処理をしてよい人だけがここまで来ることができます。 # 処理の前に e-mail が届いたことを記録します。 # #log の記録 echo ---- $DATE ---- $BACK >> $JOBNAME.log # お仕事の仕様 (2) です。 # $JOBNAME.job という file には、 # items: 項目1, 項目2, 項目3 # という行が設定できます。送られて来た e-mail の中には # この項目に相当する行があることを期待します。つまり # e-mail の format で指定されたものです。上の format を見て # ください。 set ITEMS=`awk -F' ' '$1 ~ /[Ii][Tt][Ee][Mm][Ss]:/ {print $0;exit}' < $JOBNAME.job` # 項目名の集まりを切り出します。items: のみ取り除きたいので # shift コマンドを使います。 shift ITEMS # 項目を 1 個 1個 読みだします。 foreach i ( $ITEMS ) #set TMP=`awk -F' ' '$1=='\"$i\"'{print $0;exit}' $tmpf2` # getitem : 項目の取り出すコマンドです。そのための # 環境変数 GETITEM (項目名) GETITEMF (項目名があるところ) # を設定します。 setenv GETITEM "$i" setenv GETITEMF $tmpf2 setenv TMP `getitem` # 項目の 1 行の結果は TMP に入れられます。これも念のため # log に入れられます。答案用紙を保全します。 echo "$TMP" >> $JOBNAME.log setenv GETRIGHT "$TMP" # 項目の中身は getright で取り出します。答えをとりだします。 setenv $i `getright` # さらに項目の中身で処理をしたい場合には この $i を処理しま # す。 #if ( "$i"=="" ) setenv $i "-" # この end は foreach に対する end です。全ての項目に対して # 繰り返します。 end # お仕事の仕様 (3) です。 # $JOBNAME.job という file に、 # checklist: YES # があれば、$JOBNAME.chk という file があって、e-mail を受け # 取った人の e-mail address を削除します。 # 同じ人から 2 度とることはありません。また file に残ってい # る人がまだ送っていない人です。催促は送っていない人だけに # すべきだと思います。 #Check list より削除 set CHECKLIST=`awk -F' ' '$1 ~ /[Cc][Hh][Ee][Cc][Kk][Ll][Ii][Ss][Tt]:/ {print $2;exit}' < $JOBNAME.job` if ( -e $JOBNAME.chk) then if ( "$CHECKLIST" == "YES" ) then mv $JOBNAME.chk $JOBNAME.chk$$ awk -F' ' '$1 !~ /'$BACK'/' > $JOBNAME.chk < $JOBNAME.chk$$ endif endif # お仕事の仕様 (4) です。 # $JOBNAME.job という file に、 # subprg: filename # というものがあれば、項目で設定した $i を使って、処理ができ # ます。答案の採点などが考えられます。 #更に処理する場合のプロセス起動 set SUBPRG=`awk -F' ' '$1 ~ /[Ss][Uu][Bb][Pp][Rr][Gg]:/ {print $2;exit}' < $JOBNAME.job` if ( "$SUBPRG" != "" ) then "$SUBPRG" endif # # これで全て終了です。もし結果を返すのであれば、したで # 返事をだします。 # replaymail2 complete.mes $kekka $tempf # # 最後にどんな場合でも 作業 file を消去します。 # END: rm -f $JOBNAME.chk$$ rm -f $tmpf rm -f $tmpf2 rm -f /tmp/sewanin.lock
#!/bin/csh # もし replymail2 を単独に使う場合には $BACK に # 返送 e-mail address を入れる必要があります。 # # setenv BACK who@doko.koko.jp # # 途中 C-c があっても作業 file は消します。 onintr END # PNAME に 自分の e-mail address をいれます。 set PNAME=sewanin # 作業 file です。 set tmpf=/tmp/rep$$.mail echo "Return-Path: " >> $tmpf # もし エラーがあった場合戻る先を設定します。 echo "Errors-To: ryouma@tube.ee.uec.ac.jp" >> $tmpf # @@@@@@@@@@@@@@@@@@@@@@@@ ここを直してください。 echo "Reply-To: "$PNAME@`hostname` >> $tmpf # Subject の中身も直すとよいと御読みます。 echo "Subject: Message from Auto-Replier." >> $tmpf echo "-----" >> $tmpf # ここに replymail2 の引数全部の内容を e-mail にいれます。 cat $* >> $tmpf echo "-----" >> $tmpf # ここ以下は signature です。これも使う場合には直してくださ # い。 echo " University of Electro-Communications" >> $tmpf echo " Department of Electronics Eng. Kimura-Saito Lab." >> $tmpf echo " Auto-Reply Program" >> $tmpf echo " By ryouma@tube.ee.uec.ac.jp" >> $tmpf # 最後に、日本語の e-mail は JIS(7bit) で送らないといけませ # んから nkf で変換して、$BACK あてに rmail でおくります。 nkf -j $tmpf | rmail $BACK # 作業 file を消去します。 END: rm -f $tmpf
#!/bin/csh # getitem コマンド awk -F' ' '$1=='\"$GETITEM\"'{print $0 ;exit}' $GETITEMF
#!/bin/csh # get right コマンド echo "$GETRIGHT" | awk '{ for(i=2;i<=NF;i++) printf("%s ",$i) } '
rsaito@ee.uec.ac.jp