cmd UTF8でDirでファイル名を出力させる

#前提と注意
 - シンプルですが、今は機種依存文字も多く、単純にDir出力したANSI(Shift-S)では文字化けしてしまいます。そこで完全ではありませんが、UTF8で出力します。
 - 今は検索してファイルを見つけ出すことが多いので、時間をつけてユニーク化します。
 - しかしcmdのログは時間をつけるとき一桁だと一桁になってしまいます。
 - あとCMD.exeを起動する場合と、Win+Rで起動できる場合があります。
 - 今回のOneDriveはネットワーク上のものではなく、ローカルに同期されて保存しているフォルダです。通常のDocumentフォルダをOneDriveのフォルダに置き換えているだけです。
 - ネットワーク上のOnedriveは[OneDriveをネットワークドライブとして使うまでの道のり【ネットワークドライブ登録・スタートアップ設定・容量制限緩和】](https://qiita.com/k-ashigaki/items/5f8388e45653b08bbda3)を習ってVBSでDocumentフォルダまで割り当てる方法が考えられます。
 - また、今回の記事はログの保存先をOnedriveにしていますが、あまり好ましくはないと考えられます。
 - 時間一桁問題はワンライナーでは解決できないので、そのままです
 
## ファイル名を固定すると楽

```bat
cmd /c chcp 65001 && dir %userprofile%\OneDrive\ドキュメント\*.pdf /A-D /B /OD>%userprofile%\OneDrive\ドキュメント\tt.txt && cmd /c chcp 932
```

これはコマンドプロンプトを出さなくても、Win+Rキーでも有効です。バッチファイルはバッチファイルとしてくまなくても、ワンライナーとして、Win8+Rで起動した「ファイル名を指定して実行」の欄に貼っても動きます。

次にファイル名を時間をいれていきます。

```bat
Cmd /c chcp 65001 & ^
Cmd /c CD /d "%userprofile%\OneDrive\ドキュメント\" & ^
Cmd /c Set time2=%time: =0% & ^
Set filename=%userprofile%\OneDrive\ドキュメント\log%date:~0,4%%date:~5,2%%date:~8,2%%time2:~0,2%%time2:~3,2%%time2:~6,2%.txt & ^
echo %filename% & ^
Dir "%userprofile%\OneDrive\ドキュメント\*.pdf" /A-D /B /OD>%filename%  & ^
cmd /c chcp 932 ^
cmd /c "Set filename="
cmd /c "Set time2="
```

キャレット（ハット）の後ろにはスペースが入らないように注意してください。
このコードは、Win+Rキーではうまくいきません。
また、時刻が0～9時までは一桁になるので、置換したいところです。
ところがなぜか、失敗します。

###シンプルな例
Win+R でもコマンドプロンプトからでも動きます。しかし、数字一桁問題は解決していません。

```bat
cmd /c chcp 65001 && cmd /C Dir "%OneDrive%\ドキュメント\*.pdf" /A-D /B /OD >"%OneDrive%\ドキュメント\log%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%.txt" & chcp 932
```

`/OD > %userprofile%' ここは `/OD>%userprofile%`でもうまくいきます。

次に明示的にスペースが入らない場合には、`Dir %userprofile%\onedrive\ドキュメント\*.pdf` を　`"Dir %userprofile%\onedrive\ドキュメント\*.pdf"`のように引用符でかこまなくても良いみたいです。直接スペースが入る場合には囲みましょう。
~~またクォーテーションがないほうが、Win+Rでもうまくいきます。~~
#####追記　
- 数字が一桁になる場合には`"%OneDrive%\ドキュメント\log%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%.txt"`のように出力ファイルは二重引用符で囲むと解決するようです。
- またchcpは単独でcmd /cをつけてDir命令にはあらためてcmd /cをつけないとUTF-8で出力されない場合があるようです。
多分自動で切り替わっているようです。このため、強制的にUTF-8にするにはcmd /c をDirにつける法が良いようです。

####ネットワークドライブの場合
DirのターゲットになるネットワークドライブはURL形式を使用した方がエラーにならないようです。Dir の次のフォルダ名は`\\Server\name\tarbet`のように続けます。`X:\target`のように前の部分がドライブレターが割当られていても、URLを使用したほうがいいです。
ただ、出力する方は`X:\target`のような書き方でも良いです。

####カレントを移動した例

OneDriveは微妙ですが、基本的にはDirで出力するファイルはDirと同じフォルダが良いです。
また、Cd/Dで移動した方がいいです。昔はこのようなバッチファイルが多かったと思います。
　確かに、現在ではサーバーやクライアントの領域が広がったので、こうするとログファイルが散らばる欠点があります。このため、同じフォルダにログを出力しない場合も増えています。
　しかし、フォルダ名を間違えても、ターゲットのフォルダに残ったりするので、エラー対策としては、付加した方がいいと思われます。ここは実際に使ってみて出力先をどこにするのか、判断する必要があります。

```bat
cmd /c cd /d "%OneDrive%\ドキュメント" && chcp 65001 && cmd /C Dir "%OneDrive%\ドキュメント\*.pdf" /A-D /B /OD > "%OneDrive%\ドキュメント\log%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%.txt" & cmd /c chcp 932
```

###うまくいかない例

```bat
Cmd /c chcp 65001 & ^
Cmd /c CD /d "%userprofile%\OneDrive\ドキュメント\" & ^
Cmd /c Set time2=%time: =0% & ^
Set filename=%userprofile%\OneDrive\ドキュメント\log%date:~0,4%%date:~5,2%%date:~8,2%%time2:~0,2%%time2:~3,2%%time2:~6,2%.txt & ^
Dir "%userprofile%\OneDrive\ドキュメント\*.pdf" /A-D /B /OD>%userprofile%\OneDrive\ドキュメント\log%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%.txt & ^
cmd /c chcp 932 & Set filename= & Set time2=
```
echo %filename% でみてみると、
Log20001231%time2%
というようなファイル名になってしまいます。拡張子はついていません。
また65001で文字コードも戻りません。途中でエラーがあると、そこから以降の命令が無視されるようです。

```bat
Cmd /c chcp 65001 & ^
Cmd /c CD /d "%userprofile%\OneDrive\ドキュメント\" & ^
Cmd /c Set time2=%time: =0% & ^
Set filename=%userprofile%\OneDrive\ドキュメント\log%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%.txt & ^
echo %filename% & ^
Dir "%userprofile%\OneDrive\ドキュメント\*.pdf" /A-D /B /OD>%filename%  & ^
cmd /c chcp 932 ^
cmd /c "Set filename="
cmd /c "Set time2="
```

##変数が使えないので、置換による0埋めは断念
上記のコードからこのコードに切り替えて実行しても
`C:\Users\name\OneDrive\ドキュメント\log20211031%time2:~0,2%%time2:~3,2%%time2:~6,2%.txt`

のようにtime2のままになります。
さらに、ファイルが見つかりません
といったエラーが表示され、
ログファイルに拡張子がつかない、というような状態になります。
原因が不明なので、今回はワンライナーにおいては変数を用いての0埋めが困難であるため、断念しました。

#メリット
##目的
これはファイルを検索するとき、特定のフォルダ名を検索するときにつかいます
もちろんPowershellもありますが、こちらはシンプルです。
また、UTF8で出力するので文字化けが減ります。タイ文字とかは無理ですが。
あとから検証できますし、印刷もできます。
ファイル名が重複しないので、追記や上書きのおそれもまずありません。

##デメリット
欠点としては時間が1桁になる場合がある点です。
なので、エラーが出る場合は設定した地域の時間帯の朝10時から使ってください。
または、時間帯は日付だけ使い出力ファイルを追記モードにします。%00の部分を手動で時間に変更しても良いです。
`cmd /c cd /d %userprofile%\onedrive\ドキュメント && chcp 65001 && Dir %userprofile%\onedrive\ドキュメント\*.pdf /A-D /B /OD >> %userprofile%\OneDrive\ドキュメント\log%date:~0,4%%date:~5,2%%date:~8,2%00.txt & chcp 932`

これを解決するには変数を使うしかないのですが、ワンライナーの場合、挙動がおかしいので、ここは断念しました。
バッチだとうまくいくはずなので、必要な場合はバッチファイルにしましょう
とくに夜間にバックアップするなどの場合は、バッチファイルにしましょう。

##工数、手数の簡略化、マニュアルの省力化
すると、マニュアルなどで指示するときも、コマンドプロンプトの立ち上げから説明する必要がなくなります。
また、Win+Rキーで実行できると、コマンドプロンプトを立ち上げる必要がありません。
また、バッチファイルではないため、ファイルを間違える、などの心配もありません。
メモ帳に保存しておけば、なんども使えます。また、複数のフォルダの検索もメモ帳に保存しておいて、順次実行することで、検索が可能です。

#参考文献
[ハット記号 DOSコマンド一覧 Programming Filed](https://www.pg-fl.jp/program/dos/doscmd/str_circumflex.htm)
[バッチの中でのWindows環境変数の取り扱いメモ](https://www.javadrive.jp/command/command/index4.html)
[バッチファイルで日時を扱う方法 WEB備忘録](https://hamanegi.com/memo/article/?artid=5713706d54ae0)
[環境変数の値の参照と設定(SET)](https://www.javadrive.jp/command/command/index4.html)
[Windowsのバッチファイル中で日付をファイル名に使用する](https://atmarkit.itmedia.co.jp/ait/articles/0405/01/news002.html)
[SetLocal EnableDelayedExpansionの罠とその回避方法](https://qiita.com/yz2cm/items/4983be006116c369d08b)
[コマンドプロンプトから実行しようとした際に'.' is not recognized as an internal or external command,operable program or batch file.と出たのですが](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10226684950)
[WindowsでOneDriveを活用するためのテクニック集](https://atmarkit.itmedia.co.jp/ait/articles/1411/27/news137_3.html)
[OneDriveをネットワークドライブとして使うまでの道のり【ネットワークドライブ登録・スタートアップ設定・容量制限緩和】](https://qiita.com/k-ashigaki/items/5f8388e45653b08bbda3)

#OneDriveについて
##oneDriveのドキュメントフォルダ
通常のドキュメントフォルダは
`%userprofile%\Documents`なのですが、
OneDriveの個人用の場合、日本語では
`%userprofile%\ドキュメント`
とカタカナです。
`%userprofile%\ONEDRIVE\Documents`
`%userprofile%\onedrive\Documents`
指定されたパスが見つかりません。となる。
環境変数をみると、
`OneDrive=C:\Users\name\OneDrive`
`OneDriveConsumer=C:\Users\name\OneDrive`
これを使います。
しかし、それでも英語ベースのサンプルと同じになりません。というかないみたいですけど。
[WindowsでOneDriveを活用するためのテクニック集](https://atmarkit.itmedia.co.jp/ait/articles/1411/27/news137_3.html)
によると、解決策としては、環境変数を設定したり、シンボリックリンクを作成したりすることになります。
しかし、Documentフォルダがカタカナであることは否定しようがありません。

##OneDriveをログファイルの保存先にするバッチは危険
このことから、OneDriveのドキュメントに保存するなどと行ったバッチファイルは、言語が違うと動作しないので、あまり好ましいものではないということになります。現にに　`CD %OneDrive%`で検索してもあまりヒットしません。
ログファイルはOneDrive以外で、OneDriveは`Dir %OneDrive% /A-D /B /S /OD` として検索した方がよいようです。今回は依頼をうけて、調べてOneDriveの危険性や1桁問題を納得してもらったのですが。十分注意して下さい。
この点でも、OneDriveはバックアップやファイルの簡易な共有のために用いるもので、コードをゴリゴリ動かすようなものとして設計されていないと思われます。

##この点ではDropBoxが優れている
初期設定では、DropBoxはDocumentフォルダはなく、%USERPROFILE%\Dropboxがターゲットになります。ルートにファイルがたまるような感じになりますが、こちらは言語の違いは気にしなくて良い分楽です。