Windows はコマンドラインのワイルドカードを展開してくれない
◆ * のままうけとる
◆ 展開するには glob が使える
◆ Node.js だと標準機能にないので npm からパッケージ取得必要
◆ dir などのコマンドでは展開されるので dir の結果をパイプで受け取るようにして対応させてみた
◆ 展開するには glob が使える
◆ Node.js だと標準機能にないので npm からパッケージ取得必要
◆ dir などのコマンドでは展開されるので dir の結果をパイプで受け取るようにして対応させてみた
コマンドラインで操作するときに
Linux ではなんの問題もないのですが Windows では * は * のままで渡されます
いくつかの言語で試してみてもそうだったので プログラム呼び出すときのシェル側の仕様みたいです
Windows
Linux
Windows
Linux
Windows
Linux
そういうことをするための glob という機能があります
その代わりに node-glob というパッケージが npm にあって node.js 自体のリポジトリでもこれを使ってるくらいの有名なものです
という感じです
ちょっとしたコードを書くときに毎回 npm からダウンロードは手間です
npm 使いたくなくて標準機能のみの 1 ファイルだけで完結したいときもあります
そんなときのためにパッケージ無しで Windows の Node.js でワイルドカード展開する方法を考えてみました
まず自力で glob を一から作るのは無しです
大変すぎてそんなことするなら npm を使ったほうがいいです
Windows だと * は展開されないですが dir 標準のコマンドだと普通に使えます
ということは Windows のコマンドで展開してもらったのを受け取るのが簡単そうです
こういう感じで動くようにします
Node.js だと標準入力受取も多少めんどくさいのですが こういう感じでできます
終わり方が全部違う!
Python → exit()
PHP → exit
Node.js → .exit
こういうの統一してくれればいいのにな
覚えるのめんどくさいと思ったなら Ctrl-D を押しましょう
のような感じで使えます
Node.js を使って引数を表示する例です
command *.js
のように指定した拡張子の全ファイルのようにワイルドカードを使うことは多いと思いますLinux ではなんの問題もないのですが Windows では * は * のままで渡されます
いくつかの言語で試してみてもそうだったので プログラム呼び出すときのシェル側の仕様みたいです
Windows と Linux の比較
Python
[py.py]import sys
print(sys.argv)
print(sys.argv)
Windows
>python py.py *.js
['py.py', '*.js']
['py.py', '*.js']
Linux
% python3 py.py *.js
['py.py', 'a.js', 'b.js']
PHP
[php.php]<?php
print_r($argv);
print_r($argv);
Windows
> php php.php *.js
Array
(
[0] => php.php
[1] => *.js
)
Linux
% php php.php *.js
Array
(
[0] => php.php
[1] => a.js
[2] => b.js
)
Node.js
[js.js]console.log(process.argv)
Windows
>node js.js *.js
[ 'C:\\Program Files (x86)\\Nodist\\v\\nodev8.0.0\\node.exe',
'C:\\Users\\omoti\\Desktop\\js.js',
'*.js' ]
Linux
% node js.js *.js
[ 'node', '/home/omoti/tes/js.js', 'a.js', 'b.js', 'js.js' ]
glob
*.js みたいな文字で受け取っても仕方ないので実際のファイル名にワイルドカードを展開したいですそういうことをするための glob という機能があります
Python
import sys
import glob
glob.glob(sys.argv[1])
import glob
glob.glob(sys.argv[1])
['c.js', 'dx.js']
PHP
glob($argv[1]);
Array
(
[0] => a.js
[1] => b.js
)
Node.js
残念ながら標準に glob 機能はありませんその代わりに node-glob というパッケージが npm にあって node.js 自体のリポジトリでもこれを使ってるくらいの有名なものです
const glob = require("glob")
glob.sync(process.argv[2])
glob.sync(process.argv[2])
[ 'a.js', 'b.js', 'js.js' ]
という感じです
Node.js で自力で glob
Node.js では標準で入っていないのが一番痛いところですちょっとしたコードを書くときに毎回 npm からダウンロードは手間です
npm 使いたくなくて標準機能のみの 1 ファイルだけで完結したいときもあります
そんなときのためにパッケージ無しで Windows の Node.js でワイルドカード展開する方法を考えてみました
まず自力で glob を一から作るのは無しです
大変すぎてそんなことするなら npm を使ったほうがいいです
Windows だと * は展開されないですが dir 標準のコマンドだと普通に使えます
ということは Windows のコマンドで展開してもらったのを受け取るのが簡単そうです
こういう感じで動くようにします
dir /b /s /a-d | node js.js
b: 余計な情報抜きのファイル名だけを改行区切りで表示させる
s: サブフォルダも再帰探索する
a-d: ファイルだけを表示(フォルダはいらない)
s: サブフォルダも再帰探索する
a-d: ファイルだけを表示(フォルダはいらない)
Node.js だと標準入力受取も多少めんどくさいのですが こういう感じでできます
const readline = require("readline")
const stdin_end = new Promise(resolve => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false,
})
const lines = []
rl.on("line", line => lines.push(line))
rl.on("close", eve => resolve(lines))
})
stdin_end.then(lines => {
console.log(lines)
// [ 'a.js', 'b.js', 'js.js' ]
})
const stdin_end = new Promise(resolve => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false,
})
const lines = []
rl.on("line", line => lines.push(line))
rl.on("close", eve => resolve(lines))
})
stdin_end.then(lines => {
console.log(lines)
// [ 'a.js', 'b.js', 'js.js' ]
})
ところで
今回使った Python, PHP, Nodejs ですが REPL で使っていると気づいたことが終わり方が全部違う!
Python → exit()
PHP → exit
Node.js → .exit
こういうの統一してくれればいいのにな
覚えるのめんどくさいと思ったなら Ctrl-D を押しましょう
追記 (2021/06)
PowerShell を使う場合は Get-Item コマンドレットがワイルドカードを展開してくれるので 簡単に書けますcommand (Get-Item *)
のような感じで使えます
Node.js を使って引数を表示する例です
PS C:\Data> ls tmp
ディレクトリ: C:\Data\tmp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2021/06/08 23:43 0 01.html
-a---- 2021/06/08 23:43 0 01.js
-a---- 2021/06/08 23:43 0 02.js
PS C:\Data> node -p "process.argv" (Get-Item tmp\*.js)
[
'C:\\Program Files\\nodejs\\node.exe',
'C:\\Data\\tmp\\01.js',
'C:\\Data\\tmp\\02.js'
]
COMMENT
コメント一覧 (3)
-
- 2021/06/07 10:40
-
wslのbashの上でwindowsのバイナリが動作しますので。
コマンドランチャーとして、cmd.exeやPowerShellじゃなくwslのbashを使う。
あるいはbashをワイルドカード展開用のラッパーとして使えば一挙解決ですwww
-
- 2021/06/07 10:54
-
誤解されるとなんですので
C#で次のコードをVSでコンパイルして、tcmd.exeとbash in wslでワイルドカードオプションをつけて実行させればわかります。
static void Main( string [] args ) {
foreach( var arg in args ) {
Console.Error.WriteLine( arg );
}
}
あとはbashで実行されることを前提としてオプション解析すれば済む話ではないかと、
便利な時代になったもんです。
しかし、x86の64kセグメント時代なら仕方ないとしても、せめてPowerShell は仕様変更して欲しかったなと。
-
- 2021/06/08 23:59
-
>>2
なるほど wsl なら shell で展開できるので それを前提にすれば気にしなくて済みますね
自分で普段遣いの環境で実行するなら wsl が使えますが 開発環境が入ってない PC や誰かに使ってもらうケースだと wsl が使えないこともありますし そういうときにはやっぱり困りますね
PowerShell では * を展開して欲しかったですが Get-Item 通せば展開してくれて簡単に書けたので この方法がベストかなと思っています
詳しくは記事に追記しました