treedown’s Report

システム管理者に巻き起こる様々な事象を読者の貴方へ報告するブログです。会社でも家庭でも"システム"に携わるすべての方の共感を目指しています。

※https化しました。その影響でしばらくリンク切れなどがあるかもしれませんが徐々に修正していきます。 リンク切れなどのお気づきの点がございましたらコメントなどでご指摘いただけますと助かります。

バッチファイルでコマンドの実行結果を変数に代入する

バッチファイル内であるコマンドの実行結果で得られるコンピュータ名の情報を変数に入れたいと思ったときにやってみた方法をご報告します。

例で出しているコマンドの実行結果は、環境変数で取得可能なことがほとんどなのですが、環境変数で用意されていないようなコマンドの実行結果を次のコマンド実行に反映したい処理をバッチファイルで利用する場合に役に立つTIPSだと思います。

ファイルを作って、そこから読み込む

コマンドの実行結果が一行で完結する情報だったら、単純に一時ファイルを作成して、そのファイルを変数に代入すれば良いか、ということで、リダイレクタでコマンドの実行結果となるファイルを生成して、それを代入して実行結果の取得をしていました。

例えば、
--------------------------------------------------------------
@echo off
set oput=

hostname>%CD%\hostname.txt
set /P oput=<%CD%\hostname.txt

echo %oput%

:end
del %CD%\hostname.txt
set oput=
--------------------------------------------------------------
変数oputにhostnameコマンドの実行結果を代入するに当たって、カレントディレクトリ(%CD%)にhostname.txtという一時的なテキストファイルを生成して、「set /P oput=<%CD%\hostname.txt」で変数にファイルの内容を読み込んでいます。
「echo %oput%」で表示した後は、「del %CD%\hostname.txt」で一時ファイルを削除して、要らないデータ(一時ファイル)が蓄積されないようにしておけば、やりたいことはできるかなと。最後にはdelコマンド「del %CD%\hostname.txt」で一時的に使ったファイルを消してしまえば、不要なデータがたまることもないかと。

ちなみに「%CD%」としている箇所は(環境変数の)カレントディレクトリを指定していますが、バッチファイルの実行ユーザの権限で書き込み権限のあるディレクトリ(フォルダ)なら「c:\temp」のような絶対パスで決め打ちしちゃっても大丈夫です。実行環境によって上手く指定すると良い感じ。

ただ、これはhostnameコマンドの実行結果が一行だけだから、単純にファイルを作ってそれを読み込むことで、変数にコマンドの実行結果が代入できている、という動きになります。コマンドの実行結果が複数行にわたる場合は、これでは上手く取得できないという。

コマンドの実行結果が複数の行に渡って出力

コマンドの実行結果が複数の行に渡る場合、必要な行を自分で抜き出して値を取得する必要があります。例えば「net user」コマンドでAdministratorというユーザ名が表示されるかどうかを確認する場合、
--------------------------------------------------------------
@echo off
set oput=

net user>%CD%\usrlst.txt
FOR /F %%i in ('FIND "Administrator" usrlst.txt') DO @SET oput=%%i

echo %oput%

:end
del %CD%\usrlst.txt
set oput=
--------------------------------------------------------------
前出のhostnameコマンドの実行結果取得の際には実行結果が一行でしかないので
「set /P oput=<%CD%\ファイル名.txt」
でやりたいことは出来たのですが、「net user」コマンドの場合、コマンドの実行結果出力は複数行に渡ってしまうため、(恐らく)最終行しか変数に代入されないことになってしまいます。
そこで、この行を
「FOR /F %%i in ('FIND "Administrator" usrlst.txt') DO @SET oput=%%i」
と置き換えることで、コマンドの実行結果から変数へ代入することが可能になります。
「'FIND "Administrator" usrlst.txt'」の部分で、ファイル名usrlst.txtからAdministratorという文字列を抽出、抽出した文字列を行末の「SET oput=%%i」で変数に代入しています。
ちなみに「%%i」とあるのは変数です。FORコマンドの構文で変数を利用する場合、「コマンドラインでは%i」「バッチファイル内では%%i」という記述方法で利用するルールになっています。

f:id:treedown:20200320125300p:plain
コマンドラインで直接代入してechoコマンドで表示した後、変数を初期化したら、上図のような動きになります。

しかし…この方法、予めコマンドの出力結果が分ってないと(抽出するキーワードが分らないから)ちょっと使いドコロに迷う。

ここでふと、FORコマンドの行をみて思う。ファイル作らなくて良いんじゃないの?

ファイルを生成しない方法でやりたい

バッチファイルの実行ユーザが読み書き出来る場所がない、とか、実行環境によって一時ファイルの作成がはばかられる、と言う場合、一時的にファイルを作ることができないことになります。
つまり、ファイルに書き出してから読み込むという方法が使えないので、コマンドの実行結果を変数に代入できないのか?といえば、前出のFORコマンドを利用した書式で、ファイルに書き出すことなく、コマンドの実行結果をファイルに代入できます。
--------------------------------------------------------------
@echo off
set oput=

FOR /F %%i in ('hostname') DO @SET oput=%%i
echo %oput%

:end
set oput=
--------------------------------------------------------------
大変シンプル。都度ファイルに書き出して読み込むという処理がなくなっていますので、hostnameコマンド実行結果がそのままFORコマンドの行で変数oputに代入されています。
「FOR /F %%i in ('hostname') DO @SET oput=%%i」の「'hostname'」の部分がコマンドになります。他のコマンドでも可能(ただし1行の出力結果で)です。

ファイルを作って消す作業を処理しなくて良い分だけ処理が短くて済みます。