ファイルとディレクトリの操作

LinuxBeginner
オンラインで実践に進む

はじめに

Linux では、/(ルートディレクトリ)から始まる 1 つのディレクトリツリーでファイルを管理します。すべてのファイルとディレクトリには、そのツリー内の場所を示すパスがあります。パスを読み取り、正しく使えるようになると、その後のほとんどの Linux 作業が簡単になります。

この実験では、小さな作業環境を作りながら、日常的なターミナル操作で使う基本的なコマンドを学びます。ディレクトリを移動し、ファイルを作成・編集し、データをコピー・移動し、ファイルを検索し、メタデータと inode を確認します。さらに、ハードリンクとシンボリックリンクを操作し、diff を使ってファイルとディレクトリツリーを比較します。

Linux のディレクトリツリーを確認する

このステップでは、現在の場所を確認し、ルート直下にある重要なディレクトリを調べます。その後、この実験で使う専用の作業ディレクトリを作成します。

pwd コマンドは「作業ディレクトリを表示する」という意味です。まずこのコマンドを実行して、ターミナルがどの場所から開始したかを確認します。

pwd

結果は /home/labex/project になるはずです。絶対パスは / から始まり、ファイルシステムのルートから見た場所を表します。

ファイルシステムのルート直下にあるディレクトリを一覧表示します。

ls /

etchometmpusrvar などの標準ディレクトリが表示されます。主な用途は次のとおりです。

  • /etc:システム全体の設定を格納します。
  • /home:一般ユーザーのホームディレクトリを格納します。
  • /tmp:一時データを格納します。
  • /usr:インストールされた多くのプログラムや共有リソースを格納します。
  • /var:ログやキャッシュなど、内容が変化するデータを格納します。

-d オプションを指定すると、ls は指定したディレクトリの内容ではなく、ディレクトリそのものの情報を表示します。-l オプションは詳細表示形式を指定します。

ls -ld /etc /home /tmp /usr /var

各行の先頭文字は d です。これは、その対象がディレクトリであることを示します。続く列には、権限、所有者、サイズ、時刻、名前が表示されます。

この実験で使う作業ディレクトリを作成します。-p オプションを指定すると、mkdir は存在しない親ディレクトリも作成します。また、ディレクトリがすでに存在していてもエラーになりません。

mkdir -p /home/labex/project/file-ops-lab

作成したディレクトリに移動し、新しい場所を確認します。

cd /home/labex/project/file-ops-lab
pwd

最後の出力は /home/labex/project/file-ops-lab になるはずです。

絶対パスと相対パスで移動する

このステップでは、入れ子になったディレクトリツリーを作成し、絶対パス、相対パス、移動用のショートカットを使ってその中を移動します。

まず、実験用の作業ディレクトリに移動します。

cd /home/labex/project/file-ops-lab

1 つのコマンドで、3 つの入れ子になったディレクトリを作成します。

mkdir -p navigation/alpha/beta

ここで navigation/alpha/beta/ で始まっていないため、相対パスです。シェルはこのパスを現在のディレクトリから解決します。

絶対パスを使って、一番深いディレクトリに移動します。

cd /home/labex/project/file-ops-lab/navigation/alpha/beta
pwd

特殊なパス .. は親ディレクトリを表します。beta から alpha に移動します。

cd ..
pwd

出力の末尾は /navigation/alpha になるはずです。cd - コマンドを使うと、直前の作業ディレクトリに戻れます。

cd -
pwd

beta に戻っていることを確認できます。最後に、~ はホームディレクトリを表します。パスの先頭に ~ を使って、実験用の作業ディレクトリに戻ります。

cd ~/project/file-ops-lab
pwd

絶対パスは、現在どこにいても使用できます。現在の場所が分かっている場合は、相対パスを使うとパスを短く書けます。

ディレクトリを作成してファイルに書き込む

このステップでは、ディレクトリとファイルを作成し、シェルのリダイレクトにおける上書きと追記の違いを学びます。

実験用の作業ディレクトリに移動し、2 つのディレクトリを同時に作成します。

cd /home/labex/project/file-ops-lab
mkdir documents archive

touch コマンドは、指定したファイルが存在しない場合に空のファイルを作成します。

touch documents/empty.txt

詳細表示形式で空のファイルを確認します。

ls -l documents/empty.txt

サイズは 0 バイトになるはずです。次に、> はコマンドの出力をファイルにリダイレクトします。ファイルが存在しない場合は作成し、すでに存在する場合は内容を置き換えます。

echo "Linux file practice" > documents/notes.txt

>> 演算子は、既存の内容を削除せずに出力を末尾へ追記します。

echo "Paths identify each filesystem object" >> documents/notes.txt

cat を使ってファイル全体を表示します。

cat documents/notes.txt

元の順序で 2 行が表示されるはずです。wc -l を使って行数を数えます。-lwc に行数を数えさせるオプションです。

wc -l documents/notes.txt

先頭のフィールドは 2 になるはずです。

ファイルをコピー、移動、名前変更、削除する

このステップでは、ファイルシステムのオブジェクトを変更する代表的な 4 つの操作、コピー、移動、名前変更、削除を練習します。

実験用の作業ディレクトリに戻ります。

cd /home/labex/project/file-ops-lab

cp コマンドは、コピー元をコピー先へ複製します。notes.txt を新しい名前で archive にコピーします。

cp documents/notes.txt archive/notes-backup.txt

コピー元とコピー先の両方が存在することを確認します。

ls -l documents/notes.txt archive/notes-backup.txt

一時ファイルを作成し、mv を使って 1 回の操作で移動と名前変更を行います。

echo "draft" > documents/draft.txt
mv documents/draft.txt archive/final-draft.txt

古いパスは存在しなくなり、新しいパスが存在しているはずです。

ls -l archive/final-draft.txt

ディレクトリとその中身をすべてコピーするには、再帰的に処理する -r オプションを指定します。

cp -r documents archive/documents-copy
find archive/documents-copy -maxdepth 1 -type f

rm コマンドはファイルを完全に削除します。ターミナルにはごみ箱がありません。削除しても問題ない一時ファイルを作成してから削除します。

touch disposable.tmp
rm disposable.tmp

現在のディレクトリを一覧表示して、そのパスが消えたことを確認します。

ls

disposable.tmp が表示されなければ成功です。rm を使う前に、対象のパスを必ず慎重に確認してください。

ファイルを表示、更新、検索する

このステップでは、複数行のファイルを作成し、その一部を確認します。さらに、追記リダイレクトでファイルを更新し、名前を指定して検索します。

実験用の作業ディレクトリに戻ります。ヒアドキュメントを使うと、シェルが EOF という行だけのマーカーに到達するまで、複数の行をコマンドへ渡せます。

cd /home/labex/project/file-ops-lab
cat > documents/journal.txt <<'EOF'
First entry: created a workspace
Second entry: practiced paths
Third entry: copied files
EOF

'EOF' を引用符で囲むと、ドキュメント内の特殊文字をシェルが展開しません。行番号付きでファイルを表示します。

nl -ba documents/journal.txt

-ba オプションは、すべての行に番号を付けます。最初の 2 行には head -n 2、最後の行には tail -n 1 を使います。

head -n 2 documents/journal.txt
tail -n 1 documents/journal.txt

4 行目のエントリを追記します。先ほど使った >> は、既存の 3 行を置き換えずに末尾へ出力を追加します。

echo "Fourth entry: reviewed the results" >> documents/journal.txt

結果を確認します。

tail -n 2 documents/journal.txt

次に、作業ディレクトリ内からテキストファイルを検索します。find では、. は現在のディレクトリを表し、-type f は通常のファイルだけに結果を限定し、-name はファイル名のパターンに一致するものを検索します。引用符を付けると、find が受け取る前にシェルが *.txt を展開するのを防げます。

find . -type f -name "*.txt"

出力には、作成した他のテキストファイルとともに ./documents/journal.txt が含まれるはずです。

ファイルの種類、メタデータ、inode を確認する

このステップでは、ファイル名だけでなく、Linux がファイルシステムのオブジェクトについて保持している情報を確認します。

実験用の作業ディレクトリで、file を使って 2 種類のオブジェクトを識別します。

cd /home/labex/project/file-ops-lab
file documents/journal.txt /bin/ls

journal.txt はテキストとして識別され、/bin/ls は実行可能なプログラムとして識別されます。Linux は、データの種類を識別する際にファイル名の拡張子だけに依存しているわけではありません。

stat コマンドは、サイズ、権限、所有者、タイムスタンプ、inode 番号などのメタデータを表示します。

stat documents/journal.txt

inode は、ファイルのメタデータを格納し、データへの参照を持つファイルシステム上のレコードです。ファイル名は、inode を参照するディレクトリエントリです。stat の表示形式を指定して、変化しにくいフィールドを表示します。

stat -c 'name=%n type=%F size=%s inode=%i links=%h' documents/journal.txt

%i フィールドは inode 番号、%h はその inode を参照しているハードリンクの数です。

ls-i オプションでも inode 番号を表示できます。メタデータを確認するためのファイルを作成し、その情報を調べます。

echo "inode practice" > metadata-sample.txt
ls -li metadata-sample.txt

行の先頭にある数値が inode 番号です。環境によって値は異なるため、数値そのものを覚えるのではなく、このフィールドが表す内容に注目してください。

ハードリンクとシンボリックリンクを操作する

このステップでは、Linux の 2 種類のリンクを作成し、元のファイル名を削除したときにそれぞれがどのように動作するかを確認します。

実験用の作業ディレクトリに移動し、実験用のディレクトリと元ファイルを作成します。

cd /home/labex/project/file-ops-lab
mkdir links
echo "shared inode data" > links/source.txt

オプションを付けずに ln コマンドを使うと、ハードリンクが作成されます。2 つの名前は同じ inode とファイルデータを参照します。

ln links/source.txt links/hard-link.txt

-s オプションを指定すると、シンボリックリンク(symlink とも呼ばれます)が作成されます。シンボリックリンクには、別のファイルへのパスが保存されます。

ln -s source.txt links/symbolic-link.txt

inode 番号とリンクの情報を比較します。

ls -li links

source.txthard-link.txt は同じ inode 番号になるはずです。シンボリックリンクには独自の inode があり、表示には -> source.txt が含まれます。

readlink を使って、シンボリックリンクの内部に保存されているパスを表示します。

readlink links/symbolic-link.txt

元のファイル名を削除します。

rm links/source.txt

ハードリンクを使えば、inode とそのデータに引き続きアクセスできます。

cat links/hard-link.txt

シンボリックリンクは、存在しなくなった名前を参照する状態になります。読み取ってみます。

cat links/symbolic-link.txt

No such file or directory エラーが表示されるのは想定どおりです。このエラーから、リンクオブジェクト自体は残っていますが、保存されている参照先のパスが壊れていることが分かります。この実験では、別のハードリンクが残っている限り、ハードリンクの名前を 1 つ削除してもデータは削除されないことを確認できます。一方、シンボリックリンクは保存されている参照先のパスに依存します。

Diff でファイルとディレクトリを比較する

このステップでは、diff を使って差分を見つけ、その後、2 つの小さなディレクトリツリーを同じ状態にします。

2 つのバージョン用ディレクトリを作成します。

cd /home/labex/project/file-ops-lab
mkdir -p comparison/version-a comparison/version-b

1 行だけ内容が異なる設定ファイルを作成します。

printf 'mode=production\nport=8080\n' > comparison/version-a/app.conf
printf 'mode=production\nport=9090\n' > comparison/version-b/app.conf

-u オプションを指定すると、変更箇所の前後にコンテキストを含む unified 形式で diff の結果を表示できます。

diff -u comparison/version-a/app.conf comparison/version-b/app.conf

diff は、1 つ目のファイルの行に -、2 つ目のファイルの行に + を付けて示します。終了ステータスが 0 以外になるのは、ファイルの内容が異なるためです。これは想定された結果です。

2 つ目のファイルを 1 つ目のファイルと同じ内容にしてから、-q を使って静かな形式で一致を確認します。

cp comparison/version-a/app.conf comparison/version-b/app.conf
diff -q comparison/version-a/app.conf comparison/version-b/app.conf

出力がなければ、2 つのファイルは一致しています。次に、片方のディレクトリだけにファイルを追加します。

echo "release notes" > comparison/version-a/README.txt

-r オプションを指定すると、ディレクトリツリーを再帰的に比較できます。

diff -r comparison/version-a comparison/version-b

出力には、README.txtversion-a にしか存在しないことが示されます。そのファイルをコピーして、もう一度比較します。

cp comparison/version-a/README.txt comparison/version-b/README.txt
diff -r comparison/version-a comparison/version-b

最後のコマンドで出力がなければ成功です。両方のディレクトリツリーに同じファイル内容が含まれていることを示しています。

まとめ

Linux のターミナル操作で使う基本的なファイル・ディレクトリ操作を練習しました。絶対パスと相対パスで移動し、ファイルを作成・編集し、データをコピー・移動し、一時ファイルを安全に削除し、ファイル名で検索しました。

さらに、ファイルの種類とメタデータを確認し、ファイル名と inode の関係を学びました。ハードリンクとシンボリックリンクの違いを確認し、diff を使って個々のファイルとディレクトリツリー全体を比較しました。これらの概念を身につけると、コマンドを単独の手順として暗記するのではなく、Linux のファイルがどのように扱われるかを考えられるようになります。