Windows と WSL をまたいで開発しているとき、同じ日に2回連続で「渡したコマンドが化ける」ところに突き当たった記録です。
変数に入れたパスが空文字になって届く
Windows 側から WSL の中へファイルをコピーしようとして、こういう形のコマンドを投げた。
# wsl -d Ubuntu -- = 「Ubuntu(WSL)側で、この後ろを実行して」の合図
# bash -c '...' = クォートの中身をまるごと「引数」として WSL に手渡す
# ↓ この $SRC が、あとで問題になる
wsl -d Ubuntu -- bash -c 'SRC="/mnt/c/.../テンプレ推し8_洗練案.html"; cp "$SRC" ...'返ってきたエラーは cp: cannot stat '': No such file or directory。stat は「そのファイルの情報を見る」の意味で、その対象が ''(=空っぽ)になっている。存在しないファイルを探したのではなく、ファイル名そのものが消えて届いていた。
最初は日本語ファイル名のせいだと思って ASCII だけのファイル名で試したのだが、同じように空文字で落ちた。犯人は日本語ではなく $SRC のほうだった。SRC=hello のような単純な代入でも空になります。
文字化けなら cannot stat 'テン...' のように壊れた文字が出るはずで、空文字は「変数が消えた」ときの症状です。エラーの見た目から原因を取り違えていた。
この一行が bash に届くまでには、Windows 側のシェル → wsl.exe → bash と、それぞれ別の流儀で引数を解釈する層が最低3枚挟まっています。
/mnt/c の先頭に Git Bash のインストール先がくっつく
回避のためスクリプトファイルを作り、Git Bash からこう実行した。
# 中身は書かず、スクリプトファイルの「置き場所」だけを引数で渡す形に変えた
# ところが今度は、この /mnt/c/... 自体が書き換えられた
wsl -d Ubuntu -- bash "/mnt/c/Users/.../copy_refine.sh"今度のエラーは bash: C:/Program Files/Git/mnt/c/Users/...: No such file or directory。渡したはずの /mnt/c/... の先頭に、Git Bash 自身のインストール先がくっついている。
なお Git Bash 側にはこの翻訳を止めるスイッチがあって、頭に付けるだけで通ります。
MSYS_NO_PATHCONV=1 wsl -d Ubuntu -- bash "/mnt/c/.../copy_refine.sh"試したら確かに通った。ただし毎回付け忘れる未来しか見えなかったので、自分は「PowerShell から実行する」側に寄せた。MSYS がどういう条件で変換をかけているのか、その全体像までは追えていない。「/ 始まりが怪しい」までは掴んだが、どこまでが変換対象かは分かっていないまま、動く形に寄せて先に進んだ。
エラーメッセージに「変換しました」とは書いてくれないので、症状から原因を逆算するしかありません。
回避策: 引数で渡さず、ファイルで渡す
最終的に安定したのはこの形だった。やりたい処理をシェルスクリプトファイルに書き、PowerShell 経由で wsl -d Ubuntu -- bash /mnt/c/.../script.sh と実行する。
| 渡し方 | 引数内の $変数 |
/mnt/c パス | 日本語 |
|---|---|---|---|
Git Bash から bash -c で |
消えることがある | 誤訳される | 届いた |
PowerShell から bash -c で |
消えることがある | そのまま届く | 届いた |
| スクリプトファイルに書く(PowerShell から実行) | 安全(bash が読む) | 安全 | 届いた |
日本語は今回試した範囲ではどの経路でも化けなかった(コードページを 932 に落としても届いた)。Windows は wsl.exe に引数を UTF-16 で渡すので、途中に文字コードを落とす変換が挟まらないらしいです。最初に日本語を疑ったのは完全に的外れだった。
境界を越える情報は「引数」ではなく「ファイル」に載せる、が今回の結論。ただし Git Bash から起動すれば2つめの事故はそのまま再発します(実際に再発した)。起動元を PowerShell にするところまでが1セット。
学んだこと
- Windows×WSL の境界には自動変換が複数枚挟まっていて、どれも黙って動きます。「渡したものがそのまま届く」前提で書かないようにした
- 化けたら引数を削って切り分けます。容疑者は
$変数(消える)と/始まりのパス(誤訳される)。日本語は今回シロだった - なお、この境界には別種の落とし穴もあります。Windows 側から WSL の中のファイルを書き換えたとき、「保存しました」と出ているのに中身が変わっていないことがあります。書いたら検証まで含めて1セット——仕組みの話は別の機会に
この記事は2026年7月時点の自分の理解で書いています。仕様や認識が変わってる可能性があります。