トップ回答者
どうしてもバッチファイルが意図した動作をおこなってくれず、自力で解決できないので質問します。エラー処理に詳しい方お願いします。

質問
-
毎度お騒がせいたしております。
今回は私の中ではミステリアスなことばかりなので、是非ともお手を拝借させてください。
さて問題のコードは下記のとおりです。
問題個所のコメント行の先頭には*が付けてあります。
その他のコメントはエンドユーザー向けです。
@echo off
set lgd=%~d0%~p0error_%~n0.log
echo ログファイルは%lgd%に保存されます。
if exist "%lgd%" del %lgd%
rem システムパーティションが含まれているフォルダをフルパスで指定します。
set bksysfld=a:^\bcd^\efg^\hij^\
rem dパーティションのバックアップが含まれているフォルダをフルパスで指定します。
set bkdatfld=b:^\cde^\fgh^\ijk^\
rem *まだerrflgは定義されていないので日時の出力があって問題ない
if not exist "%bksysfld%" (
echo %date% %time%
echo システムパーティションのためのフォルダが見つかりませんでした。
set errflg=1
)
rem *フォルダが存在しないのでこのエラーが表示されるのは想定どおり
if not exist "%bkdatfld%" (
rem *既にerrflgが定義されているので、日時は表示させたくない
if not defined "%errflg%" (
echo %date% %time%
set errflg=1
)
echo 指定したデータパーティション用のバックアップ保存フォルダは存在しません。
)
rem 上で指定したフォルダから最新のファイルを特定しています。
for /f %%i in ('dir /b /a-d /o-n %bksysfld%*.wim') do (
rem *ファイルが見つからないのにエラーを表示できないのはなぜか
if "%%i:~-4"==".wim" (
if not defined %errflg1 (
echo %date% %time%
set errflg=1
)
else echo 指定されたシステムバックアップ保存用フォルダには該当するファイルが見つかりませんでした。
)
else set bsfn=%bksysfld%%%i
for /f %%i in ('dir /b /a-d /o-n %bkdatfld%*.wim') do (
rem *上のfor文と同様
if "%%i:~-4"==".wim" (
if not defined %errflg% (
echo %date% %time%
set errflg=1
)
else echo 指定されたデータバックアップ保存用フォルダには該当するファイルが見つかりませんでした。
)
else set bdfn=%bkdatfld%%%i
rem *なぜここでもエラーを表示できないのか
if defined %errflg% (
echo 作業途中にエラーが生じたため、処理を中断し、Windowsに戻ります。
wpeutil reboot
)
rem *もちろんファイルが存在しないが、diskpartがスクリプトを読めなかった旨のメッセージを表示できないのか
else (
diskpart /s %~d0%~p0crtprt.txt
rem それぞれのパーティションに適応を行います。
dism apply-image /imagefile:%bsfn% /index:1 /applydir:w:\
dism apply-image /imagefile:%bdfn% /index:1 /applydir:d:\
rem システムパーティションにブートコードエントリーを書き込んでいます。
w:\windows\system32\bcdboot.exe /l ja-jp /s w:\windows s:
wpeutil reboot
)簡単に質問内容をまとめると、errflgは定義されていないことになっているのか、for____in_____do (ifをどうすれば実現できるかです。
変数の宣言や型、条件の定義などに問題がありそうというところまでは理解しているつもりなのですが、もし違うところに問題があるなら、御面倒をおかけしますが、その点もご指摘くださるととてもうれしく思います。
是非ともよろしくお願いします。
回答
-
チャブーンです。
一応コメントしておきます。
遅延環境変数の話は、for文中でbdfnをsetしたあとに
dismがbdfn指定しているところで使ってますから
本筋の処理が動かないと思うんですがどうですか。大丈夫だと思います。元ネタのソースはかなりわかりづらいですが、56/57行目の話しかなと認識していますが、ここで使う%bdfn%は、46行目で定義されていったんIF構文の外に出ています。48行目のIF構文は新しいブロックなので、%bdfn%で表示される認識です。なので、先のような言い方になっています。
あとlogファイルに何も保存されないと思う(というかファイル生成すらされない)んですが、
そこはいいんですか?3行目に変数が指定されていても、その引数を使っていないので、おっしゃる通りではありますね。私のコメントの趣旨は、一番質問者が問題にしていそうな部分にフォーカスしたもので、コードを隅から隅までれびゅーしたものではありません。このログがあってもなくても質問の本意とは離れていると判断して、とくに言及しませんでした。
私の個人的認識を述べただけで、批判の意図はありません。だからというわけでもないですが、「水も漏らさぬ完璧な回答」をこの文脈でしようとは、全く考えていません。
フォーラムは有償サポートとは異なる「コミュニティ」です。フォーラムでご質問頂くにあたっての注意点 をご一読のうえ、お楽しみください。
- 回答としてマーク win10-syoshinsya 2017年11月17日 17:03
-
© ウィンドウズスクリプトプログラマ - Windows Script Programmer 2017
構文エラーですか…。
構文ミスですが、構文エラーではありません。構文ミスを構文通り解釈してます。
それならバッチ自身を止めて、
バッチはエラーがあっても止まりません。
文やfor文の外でもerrflgの値を出力したり挑戦もしてみたのですが、%errflg=1が許されないのは最後まで疑問が残ります。
まだ理解できてないようですが、環境変数の置換は、複文全体を読み取って最初に1回行われます。したがって、複文の途中で変更しても後の祭りです。バッチの基本中の基本ですから、よく理解しましょう。
if not "%errflg%"==1 (
これも構文ミスですが、構文エラーにはならず、構文通り解釈されます。
"%errflg%"==1
は常に偽と評価されます。だって、"1"==1
は真になりません。
- 編集済み ウィンドウズスクリプトプログラマ 2017年11月18日 12:51
- 回答としてマーク win10-syoshinsya 2017年11月26日 15:33
すべての返信
-
チャブーンです。
この件ですが、直接原因は IF DEFINED構文の文法誤りであり、遅延環境変数は関係ないように思います。
IF DEFINED構文は「IF DEFINED <変数名>」であり、このケースでは「IF not DEFINED errflg (」になります。ですから、
if not defined %errflg% (
は構文上間違いです。(notが含まれることは問題ありません) 変数名として認識しない文字列を入れていたのですから、条件に引っかからないのは当然です。
で、このコードには「for文で定義したブロック内でerrflgを表示する」項目がないので、遅延環境変数は関係ないのですが、このような項目が必要な場合、以下のように設定します。サンプルなので、質問者さんのバッチとは直接関係させていませんが。
setlocal ENABLEDELAYEDEXPANSION if not defined errflg ( echo %date% %time% set errflg=1 echo エラーフラグ !errflg! が設定されました。 )
最後に余計なコメントかもしれませんが、この問題は単にコードの構文違いが原因で、「エラー処理かどうか」は完全に無関係です。スレッドタイトルに無関係な情報を付加した場合、真意が伝わりにくく、読み手が誤解する可能性が高いので、再考いただいた方がよろしいかと思います。フォーラムは有償サポートとは異なる「コミュニティ」です。フォーラムでご質問頂くにあたっての注意点 をご一読のうえ、お楽しみください。
-
© ウィンドウズスクリプトプログラマ - Windows Script Programmer 2017
エラー処理に詳しい方お願いします。
という話ではありませんね。シンタクス理解不足です。
シンタクスの理解不足と言えば、
set bksysfld=a:^\bcd^\efg^\hij^\
^によるエスケープは不要。
引用符が必要な特別な文字は次のとおりです:
次に
<スペース>
&()[]{}^=;!'+,`~
if "%%i:~-4"==".wim" (
これは何。for変数に部分文字列はないでしょう。環境変数と勘違いしてる。- 編集済み ウィンドウズスクリプトプログラマ 2017年11月16日 4:43
-
© ウィンドウズスクリプトプログラマ - Windows Script Programmer 2017
errflgをテキストで出力してif exist errflg.txtにすればよいのでは。
for文の遅延環境変数はアレなので中の変数で処理しようとしない方が無難だと思います。
dism apply-image /imagefile:%bsfn% /index:1 /applydir:w:\
は確かに遅延展開が必要ですね。
call dism apply-image /imagefile:%%bsfn%% /index:1 /applydir:w:\
%がエスケープされているので、複文読み取り時には展開されない。callで読み取り時に展開される。
ん? 複文が切れてるみたいですね。なら要らない。- 編集済み ウィンドウズスクリプトプログラマ 2017年11月16日 9:25
-
© ウィンドウズスクリプトプログラマ - Windows Script Programmer 2017
そう言えば、
if exist "%lgd%" del %lgd%
ファイルは初期化してるのに、環境変数は初期化してませんね。いいのかな。
set errflg=
普通の環境で繰り返しテストが必要でしょうから、初期化は必要でしょう。- 編集済み ウィンドウズスクリプトプログラマ 2017年11月16日 9:22
-
七辻家です。
意図を汲み取れているか微妙ですが
一応、WindowsPEで動かしてイメージの適用は出来ましたので
試してみて下さい。
並び順は「dir /o:n」のファイル名のアルファベット順でやってあります。
ファイル名に日付が含まれている事が前提ですので
日時順で行いたい場合は「dir /o:d」に変更して下さい。
@echo off set lgd=%~dp0error_%~n0.log echo ログファイルは%lgd%に保存されます。 if exist "%lgd%" del /f "%lgd%" rem システムバックアップ保存フォルダをフルパスで指定します。 set bksysfld=a:\bcd\efg\hij\ rem データバックアップ保存フォルダをフルパスで指定します。 set bkdatfld=b:\cde\fgh\ijk\ rem エラーフラグを初期化します。 set errflg= rem システムバックアップ保存フォルダの有無をチェックします。 if not exist "%bksysfld%" ( if not defined errflg echo;%date% %time% echo;システムバックアップ保存フォルダが見つかりませんでした。 set /a errflg+=1 ) >> "%lgd%" rem データバックアップ保存フォルダの有無をチェックします。 if not exist "%bkdatfld%" ( if not defined errflg echo;%date% %time% echo;データバックアップ保存フォルダが見つかりませんでした。 set /a errflg+=2 ) >> "%lgd%" rem システムバックアップ保存フォルダから最新のファイルを特定しています。 set bsfn= for /f "delims=" %%i in ('dir /b /o:n "%bksysfld%*.wim"') do set bsfn=%%i if not defined bsfn ( if not defined errflg echo;%date% %time% set /a errflg+=4 echo;システムバックアップ保存用フォルダに該当するファイルが見つかりませんでした。 ) >> "%lgd%" rem データバックアップ保存フォルダから最新のファイルを特定しています。 set bdfn= for /f "delims=" %%i in ('dir /b /o:n "%bkdatfld%*.wim"') do set bdfn=%%i if not defined bdfn ( if not defined errflg echo;%date% %time% set /a errflg+=8 echo;データバックアップ保存用フォルダに該当するファイルが見つかりませんでした。 ) >> "%lgd%" rem パーティション構成ファイルの有無をチェックします。 if not exist "%~dp0crtprt.txt" ( if not defined errflg echo;%date% %time% echo;パーティション構成ファイルが見つかりませんでした。 set /a errflg+=16 ) >> "%lgd%" rem エラーが無かったら、パーティション作成・イメージ適用・ブート書込します。 if defined errflg ( echo;作業途中にエラーが生じたため、処理を中断し、Windowsに戻ります。 ) >> "%lgd%" else ( echo;パーティション構造を作成します。 diskpart /s "%~dp0crtprt.txt" echo;それぞれのパーティションにイメージの適用を行います。 dism /apply-image /imagefile:"%bksysfld%%bsfn%" /index:1 /applydir:w:\ dism /apply-image /imagefile:"%bkdatfld%%bdfn%" /index:1 /applydir:d:\ echo;システムパーティションにブートコードエントリーを書き込んでいます。 bcdboot w:\windows /l ja-jp /s s: ) >> "%lgd%" wpeutil reboot
-
チャブーンです。
一応コメントしておきます。
遅延環境変数の話は、for文中でbdfnをsetしたあとに
dismがbdfn指定しているところで使ってますから
本筋の処理が動かないと思うんですがどうですか。大丈夫だと思います。元ネタのソースはかなりわかりづらいですが、56/57行目の話しかなと認識していますが、ここで使う%bdfn%は、46行目で定義されていったんIF構文の外に出ています。48行目のIF構文は新しいブロックなので、%bdfn%で表示される認識です。なので、先のような言い方になっています。
あとlogファイルに何も保存されないと思う(というかファイル生成すらされない)んですが、
そこはいいんですか?3行目に変数が指定されていても、その引数を使っていないので、おっしゃる通りではありますね。私のコメントの趣旨は、一番質問者が問題にしていそうな部分にフォーカスしたもので、コードを隅から隅までれびゅーしたものではありません。このログがあってもなくても質問の本意とは離れていると判断して、とくに言及しませんでした。
私の個人的認識を述べただけで、批判の意図はありません。だからというわけでもないですが、「水も漏らさぬ完璧な回答」をこの文脈でしようとは、全く考えていません。
フォーラムは有償サポートとは異なる「コミュニティ」です。フォーラムでご質問頂くにあたっての注意点 をご一読のうえ、お楽しみください。
- 回答としてマーク win10-syoshinsya 2017年11月17日 17:03
-
© ウィンドウズスクリプトプログラマ - Windows Script Programmer 2017
for /f "delims=" %%i in ('dir /b /o:n "%bkdatfld%*.wim"') do set bdfn=%%i
フルパスに拘らない、ということですね。
ファイルをアルファベットの逆順に並べ、ディレクトリ名は覗いてフルパスで1件だけ取得するバッチファイルはどのように書けばいいですか?
/S 指定されたディレクトリおよびそのサブディレクトリのすべての
ですから、フルパスを出すために/sを使うのは邪道でしょう。
ファイルを表示します。- 編集済み ウィンドウズスクリプトプログラマ 2017年11月19日 11:07
-
丁寧な回答をありがとうございます。
構文エラーですか…。それならバッチ自身を止めて、構文に誤りがあります'defined'の使用方法が間違っています?…ぐらいのメッセージが欲しいところです。
運営者様是非適切なタイトルに書き換えていただけますように。。。
今後はタイトル指定にも一層の考慮に努めたいと思います。
if
文やfor文の外でもerrflgの値を出力したり挑戦もしてみたのですが、%errflg=1が許されないのは最後まで疑問が残ります。
これはちょっと愚痴なので回答は不要です。
私は最終的に問題の部分はエラー出力に何度も使うのでサブルーチンとして
:chkerrflg
if not "%errflg%"==1 (
echo %date %time%
set errflg=1
)
exit /b
のようにして行数も減らして入れ子も少なめにして仕上げました。
皆さんいろいろな立場からのご意見ご指導感謝します。
-
© ウィンドウズスクリプトプログラマ - Windows Script Programmer 2017
構文エラーですか…。
構文ミスですが、構文エラーではありません。構文ミスを構文通り解釈してます。
それならバッチ自身を止めて、
バッチはエラーがあっても止まりません。
文やfor文の外でもerrflgの値を出力したり挑戦もしてみたのですが、%errflg=1が許されないのは最後まで疑問が残ります。
まだ理解できてないようですが、環境変数の置換は、複文全体を読み取って最初に1回行われます。したがって、複文の途中で変更しても後の祭りです。バッチの基本中の基本ですから、よく理解しましょう。
if not "%errflg%"==1 (
これも構文ミスですが、構文エラーにはならず、構文通り解釈されます。
"%errflg%"==1
は常に偽と評価されます。だって、"1"==1
は真になりません。
- 編集済み ウィンドウズスクリプトプログラマ 2017年11月18日 12:51
- 回答としてマーク win10-syoshinsya 2017年11月26日 15:33
-
質問の意図がつかみきれませんが、[ドライブ文字]:[ディレクトリ][ファイル名][拡張子]を全て含んだ物をフルパスというと理解しています。
dir /?
とするとオプションが表示されます。
その中にdir [drive letter]:\[folder name1]\[folder name2]\...\[file name(use * or ?)].[extention] /s /b /n-o
でそのファイル名のリストが表示されるとあります。
また/s /bはバッチファイルなどで扱うときに便利だとも記されています。
for /f %%i in ('dir /s /b /o-n d:\*.*() do (
set fullpath=%%i
exit /b
)
echo %fullpath%
を必要な部分に利用するかればいいと思います。
これでは意図した結果は得られませんか?
-