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: " が出るかもしれませんが、ご寛恕ください。
マクロ実装の結果
スクリプトを書く、または編集して auto_gawk のマクロボタンをクリック
ソースは上書き保存される
InputBox があらわれ、前回の入力文字列がセットされるが、
ここではブランクにして OK を押す (この例では入力ファイル不要)
実行結果がアウトプットウィンドウに表示される
なお、アウトプットウィンドウを閉じたり、表示されている文字を消去しない場合は実行結果がどんどん追記されていきます。保存しておくとログとして活用することができたりします。
もう少しマニアックにしてみる
上記の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
マクロ実装の結果
VB6製の ActiveX Dll HistoryBoxです
入力ファイル名を履歴(更新順)から入力することができます
Real(FRD)は、Runメソッドによる外部プログラム実行(GAWK起動)から リダイレクト完了、制御が戻るまでの時間を恒常的に表示します ※何もしないスクリプトを実行しても90~130ミリ秒経過する ※初回起動時、特にエクステンションのロードを伴う場合「秒単位」で経過
HistoryBox.zip(21K) ActiveX Dll HistoryBox / Closer readme必読です(07202019_003)
GAWK の強制終了
上記マクロ(マニアック)にて GAWKが無限ループに陥った時の強制終了方法です。
アプリの該当「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