0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

空白入りパスに注意しよう

0
Posted at

wine $(find . -name "*exe" | fzf) が空白入りパスで失敗した話

Ubuntu を使っているが、 Wine で Windows 向けの実行ファイルを起動するとき、カレントディレクトリ以下から .exe を探して、fzf で選択して実行する簡単なハックを使っていたところ面白いエラーが出たのでまとめた記事。

はじめに

wine $(find ./ -name "*exe" | fzf)

これは直下の *.exe ファイルをあいまい検索して起動できる便利なワンライナーだ。
あるとき次のようなエラーが出た。

wine: failed to open "./path/to/some file": c0000135

最初はWine側のDLL不足や環境破損を疑ったが、調べてみると原因はもっと単純だった。

選択されたファイルパスに空白文字が含まれており、シェルによってパスが途中で分割されていた。

この記事では、原因と対策を整理する。

問題のコマンド

上述のコマンドがやりたいことは単純で、

  1. find で実行ファイルっぽいファイルを探す
  2. fzf で候補をあいまい検索する
  3. 選択したファイルを wine に渡す

というもの。

ファイル名やディレクトリ名に空白が含まれていなければ、うまく動く。

例えば、fzf で次のようなパスを選んだ場合は問題ない。

./app/game.exe

実行されるコマンドは実質的にこうなる。

wine ./app/game.exe

しかし、パスに空白が入ると壊れる。

例えば、選択結果が次のようなものだった場合。

./example dir/game.exe

このとき、元のコマンドではシェルが空白で分割してしまう。

wine ./example dir/game.exe

つまり、wine には次のような複数の引数が渡る。

./example
dir/game.exe

本来は1つのパスとして渡したかったものが、空白で分割されてしまっている。

原因

原因は、コマンド置換 $(...) をクォートしていなかったこと。

上のコードのように書くと、$(...) の結果に対してシェルの単語分割が行われる。

そのため、結果に空白やタブなどが含まれていると、1つのパスではなく複数の引数として扱われる。

最低限の対策

まず、最小限の修正はこれ。

wine "$(find ./ -name "*exe" | fzf)"

$(...) 全体をダブルクォートする。

これで、fzf の選択結果が次のような空白入りパスでも、

./example dir/game.exe

wine には1つの引数として渡される。

wine "./example dir/game.exe"

これだけでも、今回の空白文字によるパス分割問題は解決できる。

もう少し安全な書き方

ただし、上記の対策だけだと、fzf をエスケープキーで離脱した場合などの扱いが微妙になる。単純に起動に失敗する。

そこで、選択結果をいったん変数に入れて、空でないことを確認してから実行することで解決する。

exe="$(find . -type f -iname "*.exe" | fzf)" && [ -n "$exe" ] && wine "$exe"

ただ、タイプ数が増えるので個人的にはやらないかな。

まとめ

今回のエラーは、見た目だけだとWine側の問題に見えた。

wine: failed to open "./path/to/some file": c0000135

しかし、実際にはWine以前に、シェルがパスを空白で分割していた。

つまり、問題の本体はWineではなくシェルの引数展開だった。

次のような書き方は危ない。

command $(some_command)

some_command の出力がファイルパスであり、そのパスに空白が含まれる可能性があるなら、クォートする。

command "$(some_command)"

変数に入れる場合も同じ。

file="$(some_command)"
command "$file"

ファイルパスを扱うシェルスクリプトでは、変数展開やコマンド置換をクォートすることを意識するのが重要。

Link

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?