コマンドプロンプト・プログラミング 宴

# 目次

- [コマンドプロンプト・プログラミング 序](https://qiita.com/feelinguy/items/ce75348470b583b3ae42)
- [コマンドプロンプト・プログラミング 々](https://qiita.com/feelinguy/items/0b88db4aeb41bee44f19)
- [コマンドプロンプト・プログラミング 宴](https://qiita.com/feelinguy/items/ed91ed23e7baa63471a5) <- ★
- [コマンドプロンプト・プログラミング 二次会](https://qiita.com/feelinguy/items/02c70d56b2ed039db0ee)
- [コマンドプロンプト・プログラミング 三次会](https://qiita.com/feelinguy/items/f519549b0f9e8d2a714b)
- [コマンドプロンプト・プログラミング 壮行会](https://qiita.com/feelinguy/items/76dcc87020edbeb7dc14)

# Lua

サクッと動いて、すぐ泥沼のコマンドプロンプト。
脳トレに良いのかも微妙なので Lua を導入する。

[プログラミングを覚えても#私のおすすめ](https://qiita.com/feelinguy/items/dc6012cc677016f2c9e5#%E7%A7%81%E3%81%AE%E3%81%8A%E3%81%99%E3%81%99%E3%82%81)

# nkf

下記 Vector より `nkfwin.zip` をダウンロード。

[nkf.exe nkf32.dll Windows用の詳細情報 : Vector ソフトを探す！](https://www.vector.co.jp/soft/dl/win95/util/se295331.html)

# ポータビリティ

USB メモリなどにユーティリティ群を入れて、
外出先の Win でも使えるようにしてみる。

まず、任意の作業ディレクトリを作るが、
このディレクトリは後で USB メモリにそのままコピーして
出先で使用するための環境となる。

私は今回、`usb` というディレクトリ（フォルダ）を作り、
`usb\bin` に以下のファイルをコピーした。

- `lua.exe`
- `lua53.dll`
- `luac.exe`
- `nkf.exe`：nkfwin\vc2005\win32(~)Windows-31J\nkf32.exe

## コマンドプロンプト起動バッチ

USB メモリの中に `boot.cmd` があるとする。
これはコマンドプロンプトを起動する。
私は USB メモリから直接これで起動するかもしれないし、
出先の任意パスに環境をコピーしてから起動するかもしれない。

起動したコマンドプロンプトではこうなって欲しい。

```cmd.exe
> lua -v
Lua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio

> nkf -v
Network Kanji Filter Version 2.1.4 (2015-12-12)
Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa).
Copyright (C) 1996-2015, The nkf Project.
```

そのためには `boot.cmd` は環境変数 `Path` を設定する必要がある。

### 起動パスを得る

`C:\usb` に下記のバッチがあるとすると、

```sh:currents.cmd
@echo off
echo %0
echo %~n0
echo %~d0%
echo %~p0%
echo %~dp0%
echo %~dpn0%
exit /b
```
```cmd.exe
> currents.cmd
currents.cmd
currents
C:
\usb\
C:\usb\
C:\usb\currents
```

欲しいものに近いのは `%~dp0` の `C:\usb\` だ。
この結果が `C:\usb` であればスッキリする。

```sh:pwd.cmd
@echo off
setLocal
  set pwd=%~dp0
  set pwd=%pwd:~0,-1%
  echo %pwd%
endLocal
exit /b
```
```cmd.exe
> pwd
C:\usb
```

`%pwd:~0,-1%` の意味は「先頭の文字から最後を除いたものまで」である。
つまり「最後の一文字は不要」である。

### パスを通す

```sh:boot.cmd
@echo off
setLocal
  set boot_path=%~dp0
  set boot_path=%boot_path:~0,-1%
  set path=%boot_path%\bin;%path%
  cmd.exe
endLocal
exit /b
```

① `set path=%boot_path%\bin;%path%`
② `set path=%path%;%boot_path%\bin`

`%boot_path%\bin` を優先的に探索してほしいなら ① で書く。

このコマンドプロンプト上で `Ctrl+C` を数回押した後 `exit` すると、

![cmd_exit.png](https://qiita-image-store.s3.amazonaws.com/0/105190/8adee688-13e4-2e9c-0094-d25ae08bd8f2.png)

こうなる。
そう、まだ `boot.cmd` は生きていた。

```sh:boot.cmd
@echo off
setLocal
  set boot_path=%~dp0
  set boot_path=%boot_path:~0,-1%
  set path=%boot_path%\bin;%path%
  start /b cmd.exe
endLocal
exit /b
```

`start` で別プロセスとして起動する。
オプション `/b` で新規ウィンドウを作らせないようにできる。
この後 `boot.cmd` は `exit /b` で終了する。

![cmd_result.png](https://qiita-image-store.s3.amazonaws.com/0/105190/e1838ee9-32fb-2e31-79e9-4d587042963a.png)

`setLocal` 内の環境変数も継承されている。

# Lua 版ユーティリティ

下記 `conc` は参考として書いた。

## words

```lua:words.lua
if #arg == 0 then os.exit() end

for _, word in ipairs(arg) do
  print(word)
end
```
```cmd.exe
> lua words.lua one=1, two=2, three=3;
one=1,
two=2,
three=3;

> lua words.lua   Hello   World!   "   yeah!"
Hello
World!
   yeah!

> lua words.lua はろー　わーるど！
はろー　わーるど！
```

なぜ日本語（CP932）を出力でき、全角空白で分割されないのか？
Lua の文字列は単なるバイト列（バイナリ）だからである。

## conc

```lua:conc.lua
local buf = ""

for line in io.lines() do
  if buf == "" then
    buf = line
  else
    buf = buf.." "..line
  end
end

print(buf)
```
```cmd.exe
> lua words.lua 1 2 3 4 5 | lua conc.lua
1 2 3 4 5
```

## puts

```puts.lua
local buf = ""

for _, param in ipairs(arg) do
  if buf == "" then
    buf = param
  else
    buf = buf.." "..param
  end
end

print(buf)
```
```cmd.exe
> lua puts.lua   Hello   World!   "   yeah!"
Hello World!   yeah!
```

## エイリアス

コマンドプロンプトの場合、エイリアスといえば `doskey` だが、
このエイリアスはパイプを受け取れないという問題がある。
パイプを考慮するならばバッチでラップするしかない。

`usb\bin` に `puts.lua` があるとして、そこに下記のラッパーも置く。

```sh:puts.cmd
@echo off
lua.exe %~dpn0.lua %*
exit /b
```
```cmd.exe
> puts Hello World! "yeah!"
Hello World! yeah!
```

この `puts.cmd` はラッパーのテンプレートとして使える。
ファイル名を変えさえすればいい。

# 宴のあと

もうここから先は自分と Lua の能力次第である。
最も気にすべきところは Lua には UTF-8 ライブラリはあるが、
CP932 は自力で何とかしなければならないことだ。
その手抜きのために nkf を使う。

もし二次会があるとすれば Lua と nkf をどう結びつけるかになるだろう。
最も単純なのはパイプで渡す方法だ。
もう少し気張るとすると `os.execute` `io.popen` を使うだろう。
しかし `io.popen` は Win にはちゃんと対応していない。

なんとも面倒なのである。
それでも私は PowerShell は使わない。
あれを覚えるぐらいならばコンパイラ言語を覚えた方がマシだ。

と不平をもらし会計を済ませることとした。

- [コマンドプロンプト・プログラミング 二次会](https://qiita.com/feelinguy/items/02c70d56b2ed039db0ee)