mfi.sub.jp

GAWK サクラエディタで快適に使う

  GAWK疑似統合開発環境  ~ No more fatal: ~

筆者の使うエディタはサクラエディタです。エディタとはテキストファイルや、プログラムファイル等を作成/編集する「プレーンな文字」を扱うアプリケーションです。筆者は遠い昔 WZ-Editor3 というエディタに出会い、ワードプロセッサとは違う「書くだけ」に徹した軽さと面白い数々の機能、カスタマイズと何よりその拡張性 (TX-C という文字列特化のマクロ言語)に、ハマりました。

さて、Windows 環境で GAWK4 を使用するにあたって、コマンドプロンプト (Windows10 PowerShell 含む) は無くてはならないものです。しかし、GAWK for windows の宿痾ともいえる日本語文字セットとの相性の悪さからでしょうか、とても変なエラーを吐きます。


gawk "BEGIN { print \"こんにちは世界!\" }"
 >fatal: print to "standard output" failed   (No space left on device)


これはまさに、致命的です。.....むしろソフトウェア的に

ただ、この呪われたエラーは、ファイルにリダイレクトすると発生しません。そこで、サクラエディタです。サクラエディタにはアウトプットウィンドウなるものがあって、出力からリダイレクトを受け取ってくれます。なので、マクロを作って楽をしましょう。


参考(別解コマンドプロンプト) gawk "BEGIN { print \"こんにちは世界!\" }" | more /t4 こんにちは世界! パイプで「more」に出力を繋ぐと、行頭がマルチバイト文字であってもOK (「/t4」 は、4タブ表示オプション)

下記のマクロは vbs (VBScript) で書かれています。

このマクロを起動すると、編集中の AWK スクリプトを、まず上書き保存し、スクリプトを実行します。次いで、その出力 (標準エラー出力を含む) をアウトプットウィンドウに送り、そのアウトプットウィンドウを最前面 (タブバー / ウィンドウのグループ化が前提) に表示します。たったこれだけのことで、変なエラーに悩まされることもなく、快適なコーディング / 実行環境となります。

ちなみに、編集中の AWK スクリプトがある場所をカレントディレクトリに変更しますので、読み込み用テキスト等がある場合は、同じディレクトリに置いておけば、ファイル名以外のパスを打ち込む手間が省けます。蛇足ですが、" .awk " ファイル以外には何もしません。それと、InputBox でキャンセルを選択すると、GAWK を起動せずエディタに戻ります。その際、上書き保存はします。


Homeへ戻る

_auto_gawk.vbs

1: 'サクラマクロ _auto_gawk.vbs 2: 3: Const GAWK = "gawk414" 4: Const MEMO = "D:\Progrms_StandAlone\sakura2320\macros\_auto_gawk.memo" 5: Const MAX = 20 'History size 6: Dim sdef, scmd, spath, sfilename, sargfiles, sextention, sprompt 7: Dim sar_read(), sar_write(), i, ct, num, isame 8: ReDim sar_read(MAX) 9: ReDim sar_write(MAX) 10: Call Reading(sar_read) 'Read line and input to sar_read() 11: sprompt = " << HISTORY >>" 12: For i = 1 To MAX 13: sprompt = sprompt & vbCrLf & PadNum2(i) & ": " & sar_read(i) 14: Next 15: sprompt = sprompt & vbCrLf & " ? New Files | Number | Blank " 16: sdef = sar_read(1) 'Default Text (data-inputed of just before) 17: scmd = GAWK & " -f " 18: spath = Editor.GetFilename 19: sfilename = Mid(spath, InStrRev(spath, "\") + 1) 20: sextention = Mid(sfilename, InStrRev(sfilename, ".") + 1) 21: If LCase(sextention) = "awk" Then 22: Editor.FileSave 23: sargfiles = InputBox(sprompt, "auto_gawk", sdef) 24: If Not IsEmpty(sargfiles) Then 25: 'Operate array to create History 26: If Not IsNumeric(sargfiles) Then 27: If sdef <> sargfiles And sargfiles <> "" Then 28: isame = 0 29: sar_write(1) = sargfiles 30: For i = 2 To MAX 'Search same FileName 31: If sar_read(i) = sargfiles Then 32: isame = i 33: Exit For 34: End If 35: Next 36: If isame = 0 Then 'New FileName 37: For i = 2 To MAX 38: sar_write(i) = sar_read(i - 1) 39: Next 40: Else 'Same FileName 41: ct = 1 42: For i = 1 To MAX 43: If i <> isame Then 'i=isame skip 44: ct = ct + 1 45: sar_write(ct) = sar_read(i) 46: End If 47: Next 48: End If 49: End If 50: Else 51: If Len(sargfiles) > Len(CStr(MAX)) Then 'Numeric digit check 52: sargfiles = "" 53: Else 54: num = CInt(sargfiles) 55: If num > 0 And num <= MAX Then 56: sargfiles = sar_read(num) 57: sar_write(1) = sargfiles 58: ct = 1 59: For i = 1 To MAX 60: If i <> num Then 'i=num skip 61: ct = ct + 1 62: sar_write(ct) = sar_read(i) 63: End If 64: Next 65: Else 66: sargfiles = "" 67: End If 68: End If 69: End If 70: 'Saving History and Execute 71: scmd = scmd & sfilename & " " & sargfiles 72: If sargfiles <> "" And sdef <> sargfiles Then 73: Call Writing(sar_write) 74: End If 75: Editor.ExecCommand scmd, 1 'Editing File Dir -> Current Dir 76: Editor.ActivateWinOutput 77: End If 78: End If 'Program END

79: 'Padding num 80: Function PadNum2(num) 81: If num < 10 Then 82: PadNum2 = " " & CStr(num) 83: Else 84: PadNum2 = CStr(num) 85: End If 86: End Function

87: 'History Save 88: Sub Writing(write_ar) 89: Dim objFso, objFile, i 90: Set objFso = CreateObject("Scripting.FileSystemObject") 91: Set objFile = objFso.OpenTextFile(MEMO, 2, True) 92: For i = 1 To MAX 93: objFile.WriteLine write_ar(i) 94: Next 95: objFile.Close 96: Set objFile = Nothing 97: Set objFso = Nothing 98: End Sub

99: 'History Read ...explicit reference 100: Sub Reading(ByRef read_ar) 101: Dim objFso, objFile, i 102: Set objFso = CreateObject("Scripting.FileSystemObject") 103: Set objFile = objFso.OpenTextFile(MEMO, 1) 104: For i = 1 To MAX 105: read_ar(i) = objFile.ReadLine 106: Next 107: objFile.Close 108: Set objFile = Nothing 109: Set objFso = Nothing 110: End Sub

※この _auto_gawk.vbs と「20個(行)の改行を打ち込んだ」テキストファイル _auto_gawk.memo
を作成し、サクラエディタの macros ディレクトリに配置してください。(空のファイルはエラー)
_auto_gawk.memoには、入力ファイル名を入力するたびに「ヒストリー」が作成されていきます。デフォルトのヒストリー数は 20個です。増やす場合は改行を増やしてください。
ヒストリーから入力する場合は、対応する行番号を入力します。
(番号 1-20  1は既に入力テキストとなっているので、そのままOKで動作する)
コンボボックスやリストボックスが使えないので苦肉の策です。

※3行目 の「gawk421」について、筆者がしているように gawk.exe を改名している場合はその通りにしてください。
例えば gawk414.exe と改名して使用している場合は「gawk414」のような感じです。

※4行目「_auto_gawk.memo」のパスをご自分の環境に合わせて書き換えてください。

※動かない時は、71行目の sfilename を spath に替えてみてください。

※ご使用のサクラエディタが「インストーラパッケージ」である場合、_auto_gawk.memoが起動の度に初期化されてしまい、全然役に立たない可能性があります。その場合は、macrosフォルダではない場所(Cの直下に専用フォルダを作る等)に _auto_gawk.memoを移動して、パスを変更してください。いろいろ面倒なので、「非インストーラパッケージ」の導入をお勧めします。

ご使用の前に

< gawk.exe のパスが通っていること >
< AWKPATH にカレントディレクトリの相対パスを記述していること ( .\;C:\AWK\ ) >
< 共通設定マクロ  サクラエディタにこのマクロを登録する >
< 共通設定マクロ   "キャンセル確認待ち時間" を 適宜 60 秒位に設定 >
< 共通設定ツールバー 外部マクロ  マクロボタンを設定 >


AWK スクリプトを書いて、マクロボタンで保存/実行/表示。快適です。

入力ファイル(引数)は半角スペースで区切って、複数のファイルを gawk に渡すことができます。また、20個分のヒストリーが数値入力で使えますので、入力の手間が少し省けます。

当サイトの GAWK スクリプトは全てサクラエディタのアウトプットに出力しています。
コマンドプロンプトに出力すると " fatal: " が出るかもしれませんが、ご寛恕ください。

マクロ実装の結果

sakura1.jpg

スクリプトを書く、または編集して auto_gawk のマクロボタンをクリック

sakura2.jpg

ソースは上書き保存される
InputBox があらわれ、前回の入力文字列がセットされるが、
ここではブランクにして OK を押す (この例では入力ファイル不要)

sakura3.jpg

実行結果がアウトプットウィンドウに表示される


なお、アウトプットウィンドウを閉じたり、表示されている文字を消去しない場合は実行結果がどんどん追記されていきます。保存しておくとログとして活用することができたりします。



もう少しマニアックにしてみる

上記のInputBoxを無理やりListBoxのように使う方法では、時々忘れてリストをクリックしてしまい、多少混乱してしまいます。また、サクラエディタのアウトプットはコマンドプロンプトからデータを動的に受け取るため、出力行数が多くなると極端に表示が遅くなります。例えば、100万行の出力があり、うっかりアウトプットで表示しようとすると、処理が完了して制御を取り戻すまでに十数分待たされてしまうことがあります。

以下は筆者が実際に使っているマクロです。ヒストリーボックスという入力部品(ActiveXdll)をVisualBasic6で作成(弁士様に感謝)し、専用の出力ファイル(RAMディスク上に作成)にリダイレクトして、100万行の出力でも数秒で結果を表示することができるものです。

連続実行に付随した問題で、排他制御による上書きの禁止等の面倒事を避けるために、もう一つの ActiveXdll を使って、開かれた出力ファイルのウィンドウを一度閉じるようにしています。実行後 SetWaitableTimer() により 10ミリ秒待機する仕様になっています。

1: 'サクラマクロ _auto_gawk.vbs 2: 3: Option Explicit 4: Const GAWK = "gawk414" 5: Const MEMO = "D:\Progrms_StandAlone\sakura2320\macros\_auto_gawk.memo" 6: Const OUTF = "Y:\Output.ret" 7: Const OUTWF = "Y:\Work.ret" 8: Const BAR = "#============================================================" 9: Const DT = "#DateTime : " 10: Const CM = "#CmdLine : " 11: Const TR = "#Real(FRD) : " 12: Const MS = "(msec)" 13: Dim OUTW, OUTP, ERLV, TARG 14: OUTW = ">" & OUTWF & " 2>&1" 15: OUTP = ">>" & OUTF & " 2>&1" 16: ERLV = "&If !errorlevel! EQU 0 (echo #ExitStatus: Success) " & OUTP & _ 17: "Else (echo #ExitStatus: Failure)" & OUTP 18: Dim scmd, spath, sfilename, sargfiles, sextention 19: Dim sdt, head, objShell, etime, objHist, objCl 20: scmd = GAWK & " -f " 21: spath = Editor.GetFilename() 22: sfilename = Mid(spath, InStrRev(spath, "\") + 1) 23: sextention = Mid(sfilename, InStrRev(sfilename, ".") + 1) 24: If LCase(sextention) = "awk" Then 25: Call Editor.FileSave() 26: Set objHist = CreateObject("HistoryBox.clsHist") 27: objHist.SourcePath = MEMO 28: sargfiles = objHist.ShowDialog 29: Set objHist = Nothing 30: If IsEmpty(sargfiles) = False Then 'IsEmpty()=True when Cancel 31: Set objCl = CreateObject("Closer.clsCloser") 32: Call objCl.WinClose("Output.ret - sakura") 'close if opened 33: Set objCl = Nothing 34: scmd = scmd & sfilename & " " & sargfiles 35: sdt = FormatDateTime(Date, vbLongDate) & " " & _ 36: FormatDateTime(Time, vbLongTime) 37: head = BAR & vbCrLf & DT & sdt & vbCrLf & CM & scmd 38: Call WritePost(head, OUTF) 39: Set objShell = CreateObject("WScript.Shell") 40: etime = Timer 41: objShell.Run "cmd /v:on /c " & scmd & OUTW & ERLV, 0, True 42: etime = Round((Timer - etime) * 1000, 0) 43: head = TR & etime & MS & vbCrLf & BAR 44: Call WritePost(head, OUTF) 45: objShell.Run "cmd /c Type " & OUTWF & " >> " & OUTF, 0, True 46: Set objShell = Nothing 47: Call Editor.FileOpen(OUTF) 48: End If 49: End If 'Program END

50: 'Post-scripting write 51: Sub WritePost(str, path) 52: Dim objFso, objFile 53: Set objFso = CreateObject("Scripting.FileSystemObject") 54: Set objFile = objFso.OpenTextFile(path, 8, True) 55: objFile.WriteLine str 56: objFile.Close 57: Set objFile = Nothing 58: Set objFso = Nothing 59: End Sub

マクロ実装の結果

sakura4.jpg

VB6製の ActiveX Dll HistoryBoxです

入力ファイル名を履歴(更新順)から入力することができます

sakura5.jpg

Real(FRD)は、Runメソッドによる外部プログラム実行(GAWK起動)から リダイレクト完了、制御が戻るまでの時間を恒常的に表示します ※何もしないスクリプトを実行しても90~130ミリ秒経過する ※初回起動時、特にエクステンションのロードを伴う場合「秒単位」で経過


HistoryBox.zip(21K)  ActiveX Dll HistoryBox / Closer readme必読です(07202019_003)


GAWK の強制終了

上記マクロ(マニアック)にて GAWKが無限ループに陥った時の強制終了方法です。

Ctrl+Alt+Deleteでタスクマネージャを起動 「プロセス」タブ sakura6.jpg
アプリの該当「sakura2.3.2.0」を展開(>をクリック) GAWKを選択 右クリック「タスクの終了」を実行 GAWKは停止し、Output.retが開き、ExitStatusが「Failure」となる

上記が見つからないとか、メモリが危うくスワップを起こしそうな場合は、エラーを返しませんが、下記のマクロで強制終了します。筆者はよく無限ループを起こすスクリプトを書いてしまうので、このマクロをツールバー(スクリプト実行ボタンの横に配置)に登録しています。

1 : '_kill_gawk.vbs 2 : 'gawkxxx.exe プロセスを強制終了する 3 : '戻り値は正常に戻らない 4 : 5 : Option Explicit 6 : 7 : Dim objproclist, objproc 8 : 9 : Set objproclist = GetObject("winmgmts:").InstancesOf("win32_process") 10 : For Each objproc In objproclist 11 : If Left(LCase(objproc.Name), 4) = "gawk" Then 12 : objproc.Terminate 13 : End If 14 : Next 15 : Set objproclist = Nothing

実行結果をクリア

実行結果(マニアックな方)を消去/上書きするマクロを作っておくと、意外と重宝します。アウトプットウィンドウとは違い、単なるファイルなので、実行結果は放っておくと、そのまま残り続けますし、カーソル位置を操作できないので、ある程度書き込んだら消去する必要があります。

実行結果のみに適用され、ボタン1つでクリアできるマクロは以下になります。

1 : 'サクラマクロ 実行結果をクリアする 2 : 'Output.retがフォーカスされているときのみ有効 3 : 4 : Const out ="Y:\Output.ret" 5 : Dim spath 6 : spath = Editor.GetFilename 7 : If spath=out Then 8 : With Editor 9 : .SetDrawSwitch 0 '描画更新オフ 10 : .SelectAll 0 'テキスト全選択 11 : .Delete '消去 12 : .FileSave '上書き保存 13 : .SetDrawSwitch 1 '描画更新オン 14 : .ReDraw 0 '再描画 15 : End With 16 : End If