【VBA】ChDir関数

プログラミング

特定のフォルダでコマンド実行したい

この前の続きです。

前回、以下のようなマクロを作ろうとしていました。

  1. 開いているファイルのフォルダの下にtempフォルダを作りたい
  2. tempフォルダの中に指定したファイルをコピーしたい
  3. 2でコピーしてきたファイルを使って、プログラムで処理を行い結果出力する
  4. 3でできた結果ファイルを指定した保存場所に指定した名前で保存したい
  5. tempフォルダを削除する

今回は3に関する箇所を作るときに必要となったChDir関数について書いていきたいと思います。

コマンドを実行するため現在のディレクトリを移動する

なんのこっちゃ?

と思うかも知れません。

1で作成し、2で必要なファイルをコピーしたフォルダですが、コマンドを実行する際には「カレントディレクトリ」というのを移動させる必要があります。

ChDir関数

現在のディレクトリまたはフォルダーを変更します。

※ディレクトリとフォルダは同じと思って良いです。カレント(=current=現在の)ディレクトリともいったりしますね。

ChDir関数
ChDir関数

この関数、引数をひとつ取ります。

  • 設定したいカレントディレクトリのパス

前回、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つめのデータだけ抜き出して出力しろという意味になります。

編集後記

うーん、記事をうまく書けなかった…。目的のマクロ自体はできたんだけど。