<

![endif]-->

fc2ブログ

TTLマクロメーカー

シェルスクリプトを入力し、マクロ生成ボタンを押すと、
右側のリストと一致するコマンドがTTLマクロに変換される。



 シェルスクリプト 
 コマンドリスト(タブ区切り)

waitregex:



偶数か奇数かで引用符を切り替える

※引用符はASCII コードで指定すれば、下のようなことをする必要はありません。
アホとハサミは使いようというか、アホにハサミを持たせてはいけませんね!
というわけでTTLメーカーサンプルを見てください。



複数の引用符が連なる行をTTLマクロで自動送信するの続き。

1重引用符と2重引用符の両方を含むこのようなコマンド行。
echo "$MJ" |grep 'we' |egrep "[MJ]"

まず、先に来ない方の引用符(この例では「'」)で区切った配列にするとこうなる。 *1
0| echo "$MJ" |grep 
1| we
2| |egrep "[MJ]"
 *1: ふつうsplit関数やメソッドは区切り文字は削除して返すので、we の左右の引用符はなくなる。

それらを、配列の区切り文字に使ったその引用符で囲むとこうなる。
0| 'echo "$MJ" |grep '
1| 'we'
2| ' |egrep "[MJ]"'
この時点で、重複しない引用符で囲っての文字列リテラルとなっている。
ただし、もとの文字列の 'we' の「'」はつけ直す必要がある。あとは、配列インデックスが奇数のときに、そのさらに外側を「'」には「"」で、「"」には「'」で囲んでやればいい! *2

先頭にteratermマクロ関数の「send」と、最後にLFの#10も加えてTTLマクロになった結果は、
send 'echo "$MJ" |grep '
send "'we'"
send ' |egrep "[MJ]"'
send #10

デモはTTLマクロメーカー
ソースのサンプル。先にあるのが「'」なら「"」を、「"」なら「'」を返すような関数を用意しておいて、
function qType(s){
var sq = s.indexOf("'");
var dq = s.indexOf('"');
if((sq == -1)&&(dq == -1)) return "'";
if(sq == -1) return "'";
if(dq == -1) return '"';
if(sq < dq) return '"';
}
配列で回す。
var q = qType(s);
var array_s = s.split(q);
var qq = (q =="'") ? '"' : "'";
for(var k=0; k < array_s ; k++){
if(!array_s[k]) continue;
if(k % 2 == 0) rep +='send '+q+ array_s[k] +q+"\r\n";
else rep +='send '+qq+q+ array_s[k] +q+qq+"\r\n";
}
rep += 'send #10;


*2: シェルでそういう使い方が必要な時があるとするならば、行の最初に見つかった引用符が後ろでネストして使われているとだめ。たとえば、「echo "$MJ" |grep 'a"$b"c'」


複数の引用符が連なる行をTTLマクロで自動送信する

※引用符はASCII コードで指定すれば、下のようなことをする必要はありません。
アホとハサミは使いようというか、アホにハサミを持たせてはいけませんね!
というわけでTTLメーカーサンプルを見てください。



シェルコマンド行をTeratermマクロで自動実行するには、sendln関数に文字列を渡して記述する。
echo "Michael Jackson knows we sad. but we can not heal him"

であれば、マクロファイルには次のように書く。
sendln 'echo "Michael Jackson knows we sad. but we can not heal him"'

ここで気をつけるのは引用符だ。
sendln "echo "Michael Jackson knows we sad. but we can not heal him""
と書くと、マクロは"echo "の後ろの二重引用符を文字列リテラルの終了と解釈するので、それに続くMichael~はマクロソースとして解釈できませんという構文エラーになる。

リテラルとはソースコード中の定数のことで、多くの言語では文字列を引用符で囲んで範囲を指定する。TTLマクロも「'」と「"」を使用するので、上の問題が起こらないように使用する。

しかし、下のように1行内に両方の引用符が使われているケースでは、
MJ="Michael Jackson knows we sad. but we can not heal him"
echo "$MJ" |grep 'we' |egrep "[MJ]"
sendln 'echo "$MJ" |grep 'we' |egrep "[MJ]"'
sendlnに渡す文字列の範囲を指定しようがなくなるので使えなくなってしまう。

こういうときは、文字列に改行文字を付加しないもう一つの関数、sendを使って下のように書けば大丈夫だ。
send 'echo "$MJ" |grep '
send "'we'"
send ' |egrep "[MJ]"'
send #10
最後の#10は改行のLFで、TeraTerm画面上では元のコマンドそのままに
echo "$MJ" |grep 'we' |egrep "[MJ]"
と実行される。
しかし、こんなことを手でシコシコやっていては日が暮れてしまう。自動化する方法はないか?ということで作ってみた。面白かったのは、文字列を引用符ごとに切った配列のインデックスが偶数か奇数かどうかでsendで使うべき引用符が「'」と「"」のどっちを使うのか処理できてしまうところだった。というわけで続きは次回




ttler → TTLメーカーにリニューアル中

ttlinputfile.png
という、引用符が連続したりネストしているコマンドをTTLマクロで送信したい。

TTLマクロファイルでsend関数ないしsendln関数にパラメタとして渡すには文字列全体を引用符で囲まなければならないが、そうすると「'」でも「"」でも囲む範囲の開始と終了がずれるのでマクロエラーになる。

ならばマクロファイル化するときに自動的に複数行に分解してしまおうという発想で、
出力結果はこんな感じ。
ttl_outputsamp.png

サンプルソースはこんな感じ。
var sfs = new ActiveXObject("Scripting.FileSystemObject");
var s = sfs.GetFile("ab.txt").OpenAsTextStream(1);
var f = s.ReadAll();s.Close();
  ファイルを読んで閉じてから、
var q = qType(f);
var ar = f.split(q);
var arlen = ar.length;
if(arlen ==1) document.write(ar);
else{
var qq ;
for(var i=0; i < arlen ; i++){
ar[i] = /['"]/.test(ar[i]) ? ar[i] : q+ ar[i] +q;
qq = qType(ar[i]);
qq = (q != qq) ? qq : q;
document.write("send "+ qq + ar[i] + qq +"<br>");
if(i == arlen-1) document.write("send #10");
}
}
function qType(s)
{
var dq = s.indexOf('"');
var sq = s.indexOf("'");
var iq = "'";
if(sq != -1){
if(dq == -1) iq = '"';
else if(sq < dq) iq = '"';
}
return iq;
}




Teratermマクロの引用符を入れ子する、について

追記:下のように考えなくても引用符はASCIIコードでリテラルの引用符と重複しませんでした。
"なら#34、'なら#39です。マクロ文はTTLマクロメーカーで確認できます。


ベクターから毎月メールでダウンロード数が送られてくるが、先月はttlerが50くらいあった。
いろんな環境でテストもしていないオモチャなので、そもそも動作しないという人の方が多い気もする。当初から気になっていた点には手をいれてみた。バージョンは0.2。

たとえばttlのsendlnコマンドなどに文字列を渡す場合、引用符で囲む。
しかし、その文字列内に同じ引用符を含む場合、そこで引用符の挟みが終了してしまい、残りの文字列が処理できないとしてエラーになってしまう。
またUNIXシェルでは一般に" "なら変数を展開し、' 'ならしないといった違いがある。

通常なら' 'と" "とを使い分けて入れ子にしてこれを回避する。たとえば
cat "$BIN"/aho.txt
cat $BIN/aho.txt |awk '{print}'
 というコマンドを実行したい場合、このようにする。
sendln 'cat "$BIN"/aho.txt'
sendln "cat $BIN/aho.txt |awk '{print}'"

問題は、ttlerで自動作成する場合、どちらの引用符を使うかを行から判別しなければならないところ。
判別方法は、行の最初に見つかった引用符がどちらかで、それと違う引用符をつけるということにした。(これまではデータを変数にいれてRegExpで一括置換していたので、これに行ループを入れなければならなくなったので遅くなってしまった)

しかも、
cat "$BIN"/aho.txt |awk '{print}'
 などという行になると下のようになってもうだめぽ。
'cat "$BIN"/aho.txt |awk '{print}''
そもそもttlで実行できない書き方なので、限界といえば限界かもしれない。

ちなみにこういう場合は、一行目の改行文字をエスケープして2行に書き、
cat "$BIN"/aho.txt | \
awk '{print}'
とすれば大丈夫なはず。




ttler.htaベクター送付

機能追加はいくつか考えたものの、環境に依存するので0.01のまんま。

mirrorManのときに説明書がないとダメといわれた記憶があったのだが、今回も忘れたw


ttler.hta 0.01版

とりあえずcygwinに接続して動いたもの。
ttler001

実行可コマンドのリスト。commands.iniファイル
//cmd,ポプアップ有り1
awk
nawk
bash
cat 1
rm 1
cd
・・・
タブ区切りで2つめに1を設定すると、ポップアップでマクロの続行を問い合わせ。
あまちがった、とかまずいというときは「いいえ」を選択すれば、そこでマクロ終了。
continuePop.png

でこんな感じのテキストファイルを実行して
sleep 2
csh
cat test.txt
echo "smp1" > test.txt
echo "smp2" >> test.txt
ls -l test.txt
cat test.txt
rm -f cat test.txt
sample improper command line
2回目のcatコマンドのポップアップで「いいえ」するとこんな具合
ttlcapture0.png

マクロファイル。「sample improper command line」の行は実行しないようにコメントアウト
serverIP = '10.1.68.104'
UserName = 'uid'
Password = 'pss'
UsernamePrompt = 'login:'
PasswordPrompt = 'Password:'
timeout = 0
show 0
;──┐
;接続│
;──┘cygconnect
connect serverIP
wait UsernamePrompt
sendln Username
wait PasswordPrompt
sendln Password
;────┐
;ログ出力│
;────┘
logPath = 'C:\Users\b\Desktop\'
logNm = 'test.log'
strconcat logPath logNm
logopen logPath 0 0
settitle logNm
;─────┐
;実行前確認│
;─────┘
yesnobox '実行しますか?' logNm
if result=0 goto endSub
wait '}%' '$ '
sendln 'who am i;date'
wait '}%' '$ '
sendln 'sleep 2'
wait '}%' '$ ' '? '
sendln 'csh'
wait '}%' '$ ' '? '
sendln 'cat test.txt'
call yesnoSub
wait '}%' '$ ' '? '
sendln 'echo "smp1" > test.txt'
wait '}%' '$ ' '? '
sendln 'echo "smp2" >> test.txt'
wait '}%' '$ ' '? '
sendln 'ls -l test.txt'
wait '}%' '$ ' '? '
sendln 'cat test.txt'
call yesnoSub
wait '}%' '$ ' '? '
sendln 'rm -f cat test.txt'
wait '}%' '$ ' '? '
;;;sample improper command line
goto endSub
:strScanE
;wait #10
recvln
strscan inputstr '。'
if result>1 call alertSub
wait '}%' '$ ' '? '
return
:yesnoSub
yesnobox '出力結果を確認して続行してください' logNm
if result<1 then
goto endSub
else
return
endif
:endSub
messagebox 'TTL終了' logNm
sendln 'date'
wait '}%' '$ '




ttler.hta - 画面ガラ

UNIXシェル環境で定期作業をする場合、Teratermマクロで自動化するのはよく見られる。ただし一時的な定例作業の場合、それをマクロファイル化する手間とのトレードが微妙になる場合がある。
何回も使うわけじゃないし、かといって毎回手作業でコマンドを列挙したテキストファイルからteratermのコンソールにコピペするのも面倒、もしコマンドを列挙したファイルをそのまま自動で実行できれば。そういう場合、teratermマクロにはファイルI/Oの関数も用意されている。
ただしこの場合、どんなコマンドであれ無条件に実行して突き進んでいってしまい、それが危険なケースだった場合、運用のリスクが高い。
それならば、実行できるコマンドをあらかじめ登録したもののみにし、それ以外の記述は全部除外してTTLマクロファイル化するようなツールがほしい、さらに、コマンド別にポップアップ表示やループ制御文を記述することができれば、幅広く使えるツールになるかも・・・

というわけで仕事で使っているそれを汎用化しようというのがこの休みの目標。

だが、進捗はまだ3割ほどだ。やばし。



メインのとこ
while(!inif.AtEndOfStream){
a = inif.ReadLine().split(/\t+/);
if(/^\/\/|^$/.test(a[0])) continue;
g=g.replace(new RegExp(
"^("+a[0]+".*)\r\n","mg"),
"sendln '$1'\r\nwait '}%' '$ ' '? ' '> '\r\n"
);
}
INIファイルに
ls
の行があれば、
たとえば
ls hoge
ls -lr hoge
と書いてあるファイルが
sendln 'ls hoge'
wait '}%' '$ ' '? ' '> '
sendln 'ls -lr hoge'
wait '}%' '$ ' '? ' '> '
というTTLファイルを作成する。

さて、汎用的な環境での動作確認をどうするか。最新のteratermではcygwin接続があるものの、ログイン制御とか、linuxtとかsolalisならではのコマンドとか、ああめんどくさい。予想通りのつまづきだ。


ttlMaker.hta

UNIXシェルのコマンドを列挙した任意のファイルをTeraTermマクロファイルに変換するhtaを作成する。
というわけでソフトの名前を決めて、ブログカテゴリを作成した。

職場で作って使っているものはすでにあるものの、ソースは持ち出すことができないし、
まずもって汎用環境で使用できるものとなると話は別だ。

目標地点はmirrorManと同じくVectorサイトでダウンロードランキング(カテゴリ別)1ページ目そして雑誌掲載!




while(aho.atEndofStream)

笹部 政宏
笹部 政宏
mail




フリーソフツ
Category
はてブ
Monthly Archive
New Entry
New Comment
New Trackback
RSS
Copyright © Kittens flewby me All Rights Reserved.