任意のファイルを読み込んで一括で複数のフォルダを作るコマンド比較（WindowsバッチとPowerShell）

## はじめに
テストデータ等を置いておくのに、年月度が異なる複数のフォルダを自動的に作りたいという個人的な要望が湧き上がりました。
個人的に使う自動化ツール（というほど御大層なものではないけど）を作る手段としては、ExcelVBAでもいいし、Windowsバッチ（DOSバッチ）でも、PowerShellでも、なんならPythonでもいいです。

あくまで個人的に使うもので、一回だけ（場合によっては何度か）使うコードなら、ちょっと使ったことないプログラムで書いてみようと思い立ちました。今までよく使ってきたWindowsバッチと最近ちょっと注目しているPowerShellで書き比べてみようということです。

## 前提条件
* PC環境はWindows 10 Pro
* 使うコードは「Windowsバッチ」と「PowerShell」
* ディレクトリ構成は以下の通り

```
C直下
└ test_dir
　├ PowerShell
　　├ list.txt
　　└ mkdir.ps1
　└ WindowsBatch
　　├ list.txt
　　└ mkdir.bat
```

## したいこと
作成したい複数のフォルダ名のリストが「list.txt」に書かれていて、「mkdir.ps1」または「mkdir.bat」を実行すると、同一フォルダ内に、リストに書かれた名前でフォルダが作成されるというもの。

実行するというのは、PowerShellの場合はプログラムファイル「mkdir.ps1」をダブルクリックで実行するというわけではなく、Windows PowerShell上でコードを書いて実行するということ。

また、Windowsバッチの場合は、プログラムファイル「mkdir.ps1」をダブルクリックして実行するということ。

## list.txtについて
PowerShellにしてもWindowsバッチにしても、作りたいフォルダの名前リストは同一のものとします。

今回は以下のようなリストにします。

```:list.txt
201901
201902
201903
201904
201905
201906
201907
201908
201909
201910
201911
201912
202001
202002
202003
202004
202005
202006
202007
202008
202009
202010
202011
202012

```

## Windowsバッチで書いたらこうなった
```:mkdir.bat
@echo off
pushd %~dp0
for /f %%i in (list.txt) do mkdir %%i
exit
```

すでに同名のフォルダがあったらチェックとか、フォルダの命名規則チェックとか、その他チェック系は無いので、流用したい場合は、その辺りを考慮して使っていただければと思います。

コードの意味合いは以下の通り。ざっくりとしか書かないので、詳細なことを知りたい場合はGoogle先生にお尋ねください。

```
@echo off
```
バッチを実行した時に、コードをコマンドプロンプトに表示しない。バッチをファイルのダブルクリックで実行したい時に入れるコマンドです。

```
pushd %~dp0
```
「%~dp0」に移動するコマンドです。「%~dp0」は、バッチファイルのフォルダパスを取得します。

この辺りは、[pushd／popdでフォルダーを移動する](https://www.atmarkit.co.jp/ait/articles/0609/16/news022.html "pushd／popdでフォルダーを移動する") や [バッチファイルでよく使う書き方まとめ](https://qiita.com/sta/items/8cab80fe74b8dcfa5336 "バッチファイルでよく使う書き方まとめ") が詳しくて優しいです。

```
for /f %%i in (list.txt) do mkdir %%i
```
ちょっと乱暴に書くと、「list.txt」の中身を取り出して、その取り出した１行分の文字列でフォルダを作成し、「list.txt」の最終行までループするコマンドです。

for文はオプションやらなんやらでややこしいので、 [.bat（バッチファイル）のforコマンド解説。](https://qiita.com/plcherrim/items/67be34bab1fdf3fb87f9 ".bat（バッチファイル）のforコマンド解説。") という優しい記事を参考にしてください。

```
exit
```
実行しているコマンドプロンプトを終了させるコマンドです。今回はこれだけのバッチなので、exitコマンドでも構わないですが、他バッチを呼んだり呼ばれたりしている場合は、これでは処理が途中で終了する可能性があるので、お気をつけください。

## PowerShellで書いたらこうなった
```powershell:mkdir.ps1
Get-Content list.txt | ForEach-Object { New-Item -ItemType directory -Name $_ }
```

これも、諸々チェック系は書いていないので、必要に応じてチェック処理を実装してください。

ポイントとしては「|（パイプ）」でつないでいることです。

まず前半のコマンドについてです。

```powershell
Get-Content list.txt 
```

「list.txt 」の内容を参照するコマンドレットです。
このコマンドレットに関する優しい記事は [【 Get-Content 】コマンドレット――ファイルの内容を参照する](https://www.atmarkit.co.jp/ait/articles/1608/05/news027.html "【 Get-Content 】コマンドレット――ファイルの内容を参照する") です。

次、後半のコマンドレットについてです。

```powershell
ForEach-Object { New-Item -ItemType directory -Name $_ }
```
ForEach-Objectコマンドレットで、前半部で取得した内容について、{ }内のことをするという処理です。

「foreach」と「ForEach-Object」は別物なので要注意です。

{ }内は、New-Itemコマンドレットで新しいファイルまたはフォルダを作成します。-ItemTypeオプションでdirectoryを指定しているのでここで作成するのはフォルダです。-Nameオプションでフォルダの名前を指定します。今回は「$_」ですが、前半部で取得した「list.txt」の内容です。

この辺りに関しては、 [第2回　PowerShellの基礎](https://www.atmarkit.co.jp/ait/articles/1004/15/news106.html "第2回　PowerShellの基礎") が結構親切です。バージョンが古そうな点はお気をつけいただければ、基礎知識をまとめてある点において役立つと思います。

## 比較してみての所感
実行時の速度は、計測はしていませんが、体感的にはそんなに変わらなかったと思います。

コードのバイト数は、Windowsバッチが69バイト、PowerShellが81バイトでした。行数が少ないほうが少なく見えるマジックにかかりかけました。

どっちが良いかという議論はしないです。使うべき言語の正答は開発環境や状況、各人のスキルによるので「これが正しい」とは言えないからです。

ただ、私個人的にはPowerShellのコマンドレットの方が、英単語をつないでいるので何をどうするのかわかるし、スクリプトファイルを勢いでダブルクリックしても実行されない点で、今後何か処理を作りたい時の選択肢に加わりそうです。

## おまけ
Special Thanksとして、最近お会いしたPowerShell推しのエンジニアさんを挙げておきます。

卒論の最後に書く謝辞みたいなものです。

たぶん彼のPowerShell猛プッシュ・激推し・激アツなトークを聞かなかったら、PowerShellを使ってみようとは思わなかったからです。