【VBA】ChDir関数
特定のフォルダでコマンド実行したい
この前の続きです。
【VBA】Dir関数 | ぶらたん堂
VBAを仕事で使うことがあるのですが、仕事でしか使わないからなのか、関数の覚えが悪い。その一つがDir関数。そこで記事にすることで覚えてしまおうという試みです。
前回、以下のようなマクロを作ろうとしていました。
- 開いているファイルのフォルダの下にtempフォルダを作りたい
- tempフォルダの中に指定したファイルをコピーしたい
- 2でコピーしてきたファイルを使って、プログラムで処理を行い結果出力する
- 3でできた結果ファイルを指定した保存場所に指定した名前で保存したい
- tempフォルダを削除する
今回は3に関する箇所を作るときに必要となったChDir関数について書いていきたいと思います。
コマンドを実行するため現在のディレクトリを移動する
なんのこっちゃ?
と思うかも知れません。
1で作成し、2で必要なファイルをコピーしたフォルダですが、コマンドを実行する際には「カレントディレクトリ」というのを移動させる必要があります。
ChDir関数
現在のディレクトリまたはフォルダーを変更します。
ChDir ステートメント (VBA)
Office VBA reference topic
※ディレクトリとフォルダは同じと思って良いです。カレント(=current=現在の)ディレクトリともいったりしますね。
この関数、引数をひとつ取ります。
- 設定したいカレントディレクトリのパス
前回、2の作業場所を
c:¥blatan¥temp
としたので、カレントディレクトリをここに移動します。
ChDir(“c:¥blatan¥temp”)
この関数には罠がある!
例ではCドライブとしてましたが、カレントディレクトリがCドライブ以外にある場合、ChDir関数してもそのあとの命令が上手く実行されません。
というのもカレント「ディレクトリ」を変更しても、カレント「ドライブ」は変わらないからです。
そのため、カレントディレクトリを変更する前に、カレントドライブを変える必要があります。
その関数が
ChDrive関数になります。
仮にDドライブにマクロがあるとすると、ChDirより前に
ChDrive(“D”)
と記載します。
実際のサクッと?作ったコード
Option Explicit
Sub test()
Dim target As String
Dim src As String
Dim srccopy As String
Dim savefile As String
Dim destcopy As String
Dim cmd As String
Dim wExec
Dim WSH
Dim FSO
target = ThisWorkbook.Path & "\temp"
savefile = target & "\result"
' tempフォルダがないなら作成
If Dir(target, vbDirectory) = "" Then
MkDir target
'debug MsgBox target & "がないので作りました"
End If
' コピー元ファイルをtempにコピーする
src = Cells(1, 1)
srccopy = target & "\a.txt"
' ファイルが存在しないなら処理しない
If Dir(src) <> "" Then
' コピー元に同じ名前のファイルがあるなら先に消す
If Dir(srccopy) <> "" Then
Kill srccopy
End If
' ファイルを作業フォルダにコピー
FileCopy src, srccopy
' 処理
Set WSH = CreateObject("WScript.Shell")
ChDrive Left(target, 1)
ChDir target
cmd = "awk -f ..\ssr.awk a.txt > result"
Set wExec = WSH.exec("%ComSpec% /c " & cmd)
' 終わるまで待機
Do While wExec.Status = 0
DoEvents
Loop
' できたファイルを本来の保存先にコピー
destcopy = Cells(2, 1)
' 結果コピー先に同じ名前のファイルがあるなら先に消す
If Dir(destcopy) <> "" Then
Kill destcopy
End If
' ファイルコピー
FileCopy savefile, destcopy
' パス移動(tempフォルダにいるとフォルダ削除できない)
ChDir ThisWorkbook.Path
' tempフォルダを削除する
Set FSO = CreateObject("Scripting.FileSystemObject")
FSO.DeleteFolder (target)
Set wExec = Nothing
Set FSO = Nothing
Else
MsgBox ("コピーするファイルがありません")
End If
End Sub
※今回のコードには1-5の処理全て入っています。
ChDrive Left(target, 1)
ChDrive関数ですが、どのドライブで処理しているか分かりませんので、作業ディレクトリ名の左から1文字拾ってドライブ名を取得しています。
なぜこれが必要なのか
ファイルをコピーしていたのには理由があります。
Windowsでコマンドラインでコマンドを実行する場合、ネットワークのパスを含むと失敗します。
そのため、あえてローカルにファイルをコピーしています。
単純にフルパスを予期しない動作をされるのが面倒というのもありますけど。
おまけ
残業調整のためにシルバーウィークを入れて5.5連休だったわけですが、休み前に仕事で作ろうとしていたマクロが作れてしまいました(ここでやっていることがだいたいそれ)。
3の処理だけ違いますけどね。
超どうでもいい処理内容
この記事の3の処理はゆゆゆいSSRステータス比較のCSVファイルからSSR名だけ抜き出すような命令になっています。
awk -f ..\ssr.awk a.txt > result
ssr.awkのファイルの中はこんな感じです。
BEGIN {
FS = ","
SO = STDOUT
}
NR > 1 {
print $3
}
awkと言う言語に慣れない方は分からないと思います。要約すると、コンマ区切りのCSVファイルから2行目以降の各行3つめのデータだけ抜き出して出力しろという意味になります。
編集後記
うーん、記事をうまく書けなかった…。目的のマクロ自体はできたんだけど。