Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

[bash] スペースが入ったファイル名の処理

More than 5 years have passed since last update.

スペースを含んだファイル名を bash で操作しようとした時にハマったので、メモ。
基本はls *.txtなどの出力を文字列として扱わず、ファイルパスとして扱えば良い。

例えば、下記のような bash があったとする。

touch a.txt
touch b.txt
for file in `ls *.txt`
do
  ls "${file}"
done

このケースではちゃんと動くが、ファイル名にスペースを含んだ場合は動かなくなる。

touch I\ and\ you.txt
for file in `ls *.txt`
do
  ls "${file}"
done
# 下記のように別々のファイルとみなされる
# ls: I: No such file or directory
# ls: and: No such file or directory
# ls: you.txt: No such file or directory

なぜ動かないかと言うとls *.txtの出力が文字列として評価され、次のように展開されているから。たとえば、ls *.txtをダブルクオーテーションとかで囲んでも同じエラーになる。

for file in I and you.txt

これの解決策をふたつ。まずは単純にワイルドカードを使う例。

touch I\ and\ you.txt
for file in *.txt
do
  ls "${file}"
done

こうすれば文字列として認識されないので、1ファイル毎動く。ただ、これだと使いづらい。例えば find とかで見つけたファイルを処理する場合は、次のように行う。

touch a\ and\ b.txt
find . -name '*.txt' | while read file
do
  ls "${file}"
done

シングルクォートを含んだファイルも同様に対応可能。

#シングルクォートのハイライトが変ですね Qiita さん
touch eiji\'s.txt
find . -name '*.txt' | while read file
do
  ls "${file}"
done

しかし、ここで問題が発生する場合も。例えば、ファイル名を配列に入れたい場合に次のように記述すると失敗する。

touch a.txt
touch b.txt
touch a\ and\ b.txt
files=()
find . -name '*.txt' | while read file
do
  files+=("${file}")
done
echo "${files[@]}"

これは、スペースが入ってるとかでは無くて、パイプの前後でプロセスが別になるため、filesにファイル名が足されないのが原因。

これを解決するには、パイプ出力を現在のシェル上のwhileに喰わせる上手いやり方が参考になる。

touch a.txt
touch b.txt
touch a\ and\ b.txt
files=()
while read file
do
  files+=("${file}")
done < <(find . -name '*.txt')
echo "${files[@]}"

doneの後ろの<<が離れているのがポイント。
見てしまえば、なるほどな、と思うが、思いつかないなー。
普通にperlとかに逃げそうw。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away