こんにちは、Reoです。
現在はフリーランスのインフラエンジニアとして働きながら、インフラ特化の学習サービス「InfraDojo(インフラ道場)」を運営しています。
Linuxで、存在するはずのファイルを指定したのに、
No such file or directory
と表示されたことはありませんか?
ファイル名にスペースが含まれている場合、ひとつのファイル名が、複数の引数としてコマンドへ渡っている可能性があります。
今回は、練習用のファイルを使い、クォートの有無で何が変わるのかを確認します。
1. ファイル名にスペースは使える
Linuxでは、次のようなスペースを含むファイル名を使えます。
meeting notes.txt
ただし、コマンドで指定するときには書き方に注意が必要です。
例えば、次のコマンドを見てみましょう。
cat meeting notes.txt
これは、meeting notes.txtというひとつのファイルを指定したことにはなりません。
Bashは、クォートされていないスペースを区切りとして扱うため、catには次の2つが渡ります。
meeting
notes.txt
このように、コマンドへ渡すファイル名や値などを「引数」と呼びます。
スペースを含む名前をひとつの引数として渡すには、次のようにクォートで囲みます。
cat "meeting notes.txt"
実際に試していきましょう。
2. 練習用のファイルを準備する
この記事ではBashを使います。Bashが利用できる環境で、まず次を実行してください。
bash
以降は、同じターミナルで上から順番に操作します。
練習用の一時ディレクトリを作り、そこへ移動します。
practice_dir=$(mktemp -d) && cd "$practice_dir"
エラーが出ていなければ、ファイルを作成します。
printf '%s\n' 'meeting notes' > 'meeting notes.txt'
ここでは、meeting notes.txtという名前のファイルに、meeting notesという1行を書き込みました。
ファイル名をダブルクォートで囲んで、内容を確認します。
cat "meeting notes.txt"
出力:
meeting notes
シングルクォートでも、今回のファイル名を指定できます。
cat 'meeting notes.txt'
出力:
meeting notes
どちらも、スペースを含む名前をひとつの引数として渡せています。
3. クォートがないと、何が変わる?
今度は、クォートを外してみます。
cat meeting notes.txt
今回の練習環境には、meetingとnotes.txtというファイルは作っていないため、エラーになります。
英語表示の環境では、例えば次のように表示されます。
cat: meeting: No such file or directory
cat: notes.txt: No such file or directory
エラー文は、環境の言語設定などによって異なります。
注目したいのは、エラーに出ているファイル名が2つに分かれていることです。
指定したかった名前:
meeting notes.txt
実際に渡った名前:
meeting
notes.txt
ファイルは存在していても、コマンドへ渡した名前が違えば開けません。
「名前を見た目どおりに入力したのに、見つからない」というときは、クォートも確認してみてください。
4. コピーするときは、コピー元とコピー先をそれぞれ囲む
ファイルをコピーするときも、同じ考え方です。
次のコマンドを実行します。
cp "meeting notes.txt" "meeting notes backup.txt"
この場合、cpへ渡しているのは次の2つです。
| 役割 | ファイル名 |
|---|---|
| コピー元 | meeting notes.txt |
| コピー先 | meeting notes backup.txt |
コピーしたファイルを確認します。
cat "meeting notes backup.txt"
出力:
meeting notes
ポイントは、コピー元とコピー先を、それぞれ別のクォートで囲むことです。
コマンド全体をまとめて囲むのではなく、「ひとつの引数として渡したい範囲」を囲みます。
5. 変数に入れたファイル名も、ダブルクォートで囲む
シェルスクリプトでは、ファイル名を変数に入れて使うこともあります。
まず、練習用の変数を設定します。
practice_file='meeting notes.txt'
その変数を使って、ファイルを読みます。
cat "$practice_file"
出力:
meeting notes
ここで、次のようにクォートを外すと、通常のBashの設定ではスペースで分割されます。
cat $practice_file
変数への代入時にクォートを付けていても、変数を使うときのクォートが不要になるわけではありません。
Bashでは、ダブルクォートの外で展開された変数の値は、単語分割などの対象になります。"$practice_file"のように囲むことで、今回の値をひとつの引数として渡せます。参考:Bashマニュアル「Word Splitting」
違いを目で確認するには、次のコマンドも使えます。
クォートなし:
printf '<%s>\n' $practice_file
出力:
<meeting>
<notes.txt>
クォートあり:
printf '<%s>\n' "$practice_file"
出力:
<meeting notes.txt>
printfが受け取った値を、< >で囲んで表示しています。
クォートの有無によって、2つに分かれる場合と、ひとつにまとまる場合があることを確認できます。
6. シングルクォートとダブルクォートの違い
ここで、2種類のクォートを整理しておきましょう。
| 書き方 | 今回押さえたい特徴 |
|---|---|
'文字列' |
中身を文字列として扱い、変数を展開しない |
"文字列" |
スペースを含む値をまとめながら、変数は展開する |
例えば、次のコマンドを実行します。
printf '%s\n' '$practice_file'
出力:
$practice_file
シングルクォートの中では、$practice_fileという文字列がそのまま使われます。
次に、ダブルクォートへ変えます。
printf '%s\n' "$practice_file"
出力:
meeting notes.txt
今度は、変数に入れた値が表示されました。
まずは、次の使い分けから始めると整理しやすいです。
- 固定のファイル名をそのまま指定する:
'meeting notes.txt' - 変数に入れたファイル名を使う:
"$practice_file"
通常のダブルクォート内では、変数展開のほかにコマンド置換なども働きます。ここでは、ファイル名を扱うための基本的な違いを押さえましょう。
7. ファイルが見つからないときの確認ポイント
今回のような場面では、次の順番で確認してみてください。
-
pwdで、現在いるディレクトリを確認する -
lsで、対象のファイルがあるか確認する - ファイル名のスペースや大文字・小文字を確認する
- スペースを含む名前をクォートで囲んでいるか確認する
- 変数を使っている場合は、
"$変数名"になっているか確認する
特に、エラー文に表示された名前が途中で分かれていたら、引数の区切りを見直す手がかりになります。
練習が終わったら、最初に起動したBashを終了します。
exit
これで元のシェルに戻ります。練習用ファイルは一時ディレクトリに残ります。
Linuxを、入力した結果まで理解する練習にしたい人へ
今回のポイントは、自分が入力した文字列と、コマンドが受け取る引数を分けて考えることです。
同じファイル名でも、クォートの付け方によって渡り方が変わります。
こうした違いを実際に試すと、エラーが出たときに確認できることが増えていきます。
自分が運営するInfraDojo(インフラ道場)では、ブラウザ上の学習用シミュレーターで、課題を読み、コマンドを入力し、結果を確認しながらLinuxの基本操作を学べます。
環境構築不要で、無料の入門コースから取り組めます。
▼ InfraDojo(インフラ道場)