DOSバッチでバッチファイルを読み込んで編集して書き出したかった


エンジニア一年生と「rem削除」の闘い

結論:やめた方がいい

(少なくとも初心者は)

前提

(免罪符ともいう)
本稿を書いている私は刺身を好きなだけ食える生活がしたいだけの、2019年8月から黒い画面を触り始めたバチバチの初学者です。
完全ではない情報、詰めの甘い部分、もちろん誤った認識等があれば、申し訳ありません。ご指摘ください。
キツい言葉はやめてください。こころおれる。

要件

1) C:\koko\soko\asoko.bat 的な感じで保存されているバッチファイルの全文から「rem 」を削除する
2) できれば C:\koko\soko 以下にあるすべてのbatファイルに同じ動作を行う
3) さらに可能なら C:\koko\soko にあるファイルはそのままバックアップとして保管し、 C:\koko\doko に実行用ファイルとして「rem 」を削除したファイルを置く
これができれば良かった。

バッチファイルでやる

要件1)

sample1
@echo off
setlocal enabledelayedexpansion
set motoFile="C:\koko\soko\asoko.bat"
set atoFile="C:\koko\soko\asoko2.bat"

for /f "delims=" %%A in (
  %motoFile%
) do (
  set line=%%A
  echo %%A | findstr /c:"rem " >  nul
  if !ERRORLEVEL!==0 (
    echo !line:~4! >> %atoFile%
  ) else (
    echo !line! >> %atoFile%
  )
)

endlocal

これが鬼門
読み込みと書き出し自体に問題は発生しなかったが、で

set LOG="nanyara.log"

等したログファイルが
- %LOG%というお名前で
- カレントディレクトリに
- 完全な状態で
作成されるという現象が発生。


※「完全な状態」... echo %date% %time% start > %LOG% 等して書き出している内容がログとして記載された状態


要件2)

要件1のfor文をちょっといじる。

sample2
@echo off
setlocal enabledelayedexpansion
set motoFile="C:\koko\soko\asoko.bat"
set atoFile="C:\koko\soko\asoko2.bat"
set here="C:\koko\soko"

for /f "usebackq" %%A in (
  `dir /s %here% ^| findstr /e /c:".bat" `
) do (
  REM === ここでは%%Aは「.batで終わるファイルのフルパス」を持っている
  call :remDel %%A
)

:remDel
REM === %1の中身は「フルパス」なのでいいようにいじる
REM === (下記はファイル名と拡張子のみにしている)
set %motoFile%=%~nx1
set %atoFile%=ato_%motoFile%

for /f "delims=" %%B in (
  "%1"
) do (
  set line=%%B
  echo %%B | findstr /c:"rem " >  nul
  if !ERRORLEVEL!==0 (
    echo !line:~4! >> %atoFile%
  ) else (
    echo !line! >> %atoFile%
  )
)
exit /b

endlocal
  • dir /s の「実行結果はフルパスで取得される」と dir /b の「実行結果をファイル名のみで取得する」は競合して/sが勝つ
  • 再帰検索が必要な場合は実行結果を加工する必要がある → 引数として文字列を渡す必要がある このあたりがちょっと知恵熱出そうになった。 「今この変数は何を抱えているのか」を都度echoで確認していた。 ***

要件3)

@echo off
setlocal enabledelayedexpansion
set here="C:\koko"
mkdir %here%doko
set doko="%here%\doko"

REM === まずやること → 対象のファイルをコピーする
for /f "usebackq" %%a in (
  `dir /s ^| findstr /e /c:".bat"`
) do (
REM === 別の塊を呼んでファイル名を編集 → コピー
  call :rename %%a
)
goto:EOF

:rename
REM === フルパスを拡張子ありとなしに加工する
set nameEx=%~nx1
set name=%~n1

REM === 書き込み用ファイルを作成する
copy %1 %doko%\re_%name%.txt
type nul > %doko%\re_%name%.txt
set reName=%re_name%.txt

REM === 別のfor文を呼んで対象のファイルを書き込む
call :edit %nameEx% %reName% 

exit /b


:edit
REM === rem を削除して書き込む
set from=%1
set to=%2

for /f "delims=" %%A in (
  %now%testfiles\%from%
) do (
  set line=%%A
  echo %%A | findstr /b /c:"rem " >nul
  if not !ERRORLEVEL!==1 (
    echo !line:~4! >> %now%testfiles\%to%
  ) else (
    echo !line! >> %now%testfiles\%to%
  )
)

exit /b
endlocal

あっちいってこっちいってって感じで微妙に気持ち悪いけど筆者の限界がここだった。

次回へ続く

長くなってしまった。
一応動いたはずのテストコードを編集して記載しているものの編集ミス等で動かない可能性もあるコードたちです。致命的な何かが起こっても責任は負えません。
ただしご指摘をいただければありがたく修正します。