犬でもわかるバッチファイルの作り方~カレントディレクトリを意識しよう!

Windows

入社してもうすぐ2か月経つんですが、バッチファイルというものを初めて知りました。

いやーバッチファイルって簡単な動作でいろいろなことをやってくれるので便利ですね!

そんなレベルの人間がバッチファイルをつくった際に「これ重要だな」と思った部分を皆様にご紹介しようと思います。

よく使う汎用的なコマンド編

bat、vbs、ps1の3つのスクリプト実行ファイルの使い分け編

再起動後も処理を続ける方法編

相対パスで作ること!

一番初めにバッチファイルを作った時、上司にアドバイスされました。

パスの指定は絶対パスではなく相対パスを使ってください。

なぜ絶対パスではいけないのでしょう?

当時、バッチファイルをどこで動かすかはっきり決まっておらず、私は仮に”C:\”で動かす想定でフォルダを作りバッチファイルを格納していました。

もし絶対パスでそのまま作っていた場合、何かしらの理由で”C:\”にバッチファイルの入ったフォルダが置けなかったらすべてのバッチファイルが動作しなくなってしまいます。フォルダが移るたびにわざわざバッチファイルを書き換えてから実行する・・・なんとも無駄な時間ですね。

そのためにもバッチファイルでパスを指定するときは必ず相対パスにしましょう。

カレントディレクトリにご用心

ファイルはどこだ?

というわけでバッチファイルを作り直して、起動実験を開始しました。場所はアクセスしやすいデスクトップ上に専用のフォルダを用意しました。

今回はレジストリの値を変更するので、ダブルクリックしたらバックアップをバッチファイルと同じフォルダに作成しその後書き換えを行うというスクリプトを作成。

というわけでダブルクリック!・・・すると管理者権限がないことを理由に処理が実行されませんでした。そうか、レジストリを弄るバッチファイルだったので管理者じゃないと動かないんですね。うっかりしてました。

さぁバッチファイルを右クリック→管理者として実行をクリックして再度起動します!

ふぅ、今度は無事に成功しました。さてさてバックアップファイルは・・・あれ?同じフォルダにないぞ?

プログラム名で検索して待つこと数分、ようやく発見!保管場所は

C:\Windows\System32

えぇ?なぜこんなところに?

相対パスの落とし穴

皆さんご存じの通り相対パスというのは「実行しているファイルの現在の位置から見た目的のファイルまでの道」です。今回の目的のファイルというのはレジストリのバックアップですね。

そのパスを私は”.\backup.reg”として作成するように指定していました。こうすることでバッチファイルと一緒の階層に目的のファイルが作成されるのが理想形だったのです。

しかしここで「管理者権限での実行」という想定外の事態が起きました。実はコマンドプロンプトやPowershellは普通に動かすのと管理者権限で動かすときである違いがあるのです。

それが「カレントディレクトリ」!

簡単に言えば現在作業中のフォルダのことを指します。サインイン中のユーザーとしてGUIから実行した場合、実行したファイルがある場所がカレントディレクトリとなります。

しかし管理者として実行すると、カレントディレクトリは “C:\Windows\System32″ になります。

この場合、相対パスで書かれていた”.\backup.reg”は絶対パスに直すと“C:\Windows\System32\backup.reg”と判断されてしまいます。

画像は同じ場所でコマンドプロンプトを実際に起動してみた時の物です。一番下の行が違うのが分かります。これがそれぞれのカレントディレクトリです。

だから全く見覚えのないフォルダに入ってたんですね。・・・ってそれじゃ困るんですよ!

何とか元のフォルダに移動させなければなりません。しかし一度バッチファイルを起動させたらそのまま処理が進んでしまい、ほかのコマンドを打ち込む余裕なんてありません。となると必要なのはバッチファイルにカレントフォルダを指定するコマンドを入れること。でも絶対パスを入れることはできない。さてどうすればいいのでしょう?

合言葉は「cd /d %~dp0」

ここで登場するのが本日の目玉のこのコマンド!「cd /d %~dp0」です!あっ、文字化けじゃないので安心してください。でもパッと見ただけじゃわかりにくいですね。というわけでそれぞれを細分化して見ていきましょう。

「cd /d」はカレントディレクトリの移動を表す

まずはこの「cd /d」。これはそのままズバリ「カレントフォルダを指定のフォルダに移動する」というコマンドです。

例えばコマンドプロンプトで”cd C:\”と打てばカレントディレクトリが”C:\”に移動します。

ただこのコマンド一つ欠点があるんです。それはドライブ間の移動ができないこと。それを補助するのが「/d」。これを「cd」の後ろにつけるとドライブの制限を気にすることなく移動できるようになります。

「%~dp0」は起動ファイルの絶対パス

後はこちらの「%~dp0」。上のコマンドはまぁ何を示しているかなんとなくわかりましたがこっちは本当に訳が分かりません。一つ一つ段階を踏んでいきましょう。

まずこれらを「d」「p」「%0」と「~」に分解します。「d」がドライブの文字の指定。「p」がファイル名以外のパス。そして「%0」がファイル名をさします。つまり「%dp0」は実行されているファイルのパスを表します。

ところが、このままだとフォルダ名に空白がある場合の対策として、自動的にパス自体をダブルクオート(“)に囲んでしまいます。そうなると挙動が不安定になるので、間に「~」を入れることでダブルクオートを外すことができます。

そう「cd /d %~dp0」とはつまり「カレントディレクトリを、現在実行しているファイルのあるフォルダへと移動させる」ということをコマンド化したものなのです。

実際に「cd /d %~dp0」を書いたバッチファイルを作成して実行するとこうなります。

これをバッチファイルでの処理を開始する前に加えておけば相対パスで書いたスクリプトも問題なく動きます。

ちなみに「cd /d %~dp0」のあとにさらにフォルダ名を入れるとカレントディレクトリが追加したフォルダまでのパスになります。直下のフォルダ内にあるプログラムを起動したい時などに活用してみてください。

新しい書き方「pushd %0¥..」(2021年6月追記)

pushd %0¥..

実はこの書き方は、移動先のドライブがカレントディレクトリのドライブと違っていても移動できます。

「pushd」→カレントディレクトリの移動

「%0¥..」→絶対パス

問題は続く

よしこれでバッチファイルの起動は問題ないぞ!

さてさてダブルクリックで起動・・・あっ、また管理者権限のこと忘れてた。でも毎度毎度バッチファイルを右クリック→管理者として実行するのも面倒だなぁ。どうしよう・・・。

では続きをどうぞ。