第4章 ファイル操作
ファイルの作成・コピー・移動(リネーム)・削除を行う4つのコマンドを扱います。
touch — 空ファイルの作成
$ touch memo2.txt
$ ls
memo.txt memo2.txt notes readme.txt
すでに存在するファイルに対して touch を実行すると、中身は変えずに更新日時だけを現在時刻に更新できます。「ファイルの中身は変更していないが、更新日時だけ最新にしておきたい」という場面(ビルドツールの再実行判定など)で実務でも使われるテクニックです。
| オプション | 意味 |
|---|---|
-a | アクセス日時のみ更新する |
-m | 更新(修正)日時のみ更新する |
-t [[CC]YY]MMDDhhmm[.ss] | 日時を指定して設定する |
また、touchで新規作成されるファイルの中身は必ず空(0バイト)です。テキストエディタを開かずに「とりあえず名前だけ決めたファイルを用意しておきたい」というときに便利です。中身を書き込みたい場合は、この章のあとで扱う nano のようなエディタや、第8章で扱うリダイレクト(>)を使います。
cp — ファイルをコピーする
cp コピー元 コピー先 の順に指定します。
| オプション | 意味 |
|---|---|
-r | ディレクトリごと再帰的にコピー(recursive) |
-i | コピー先に同名ファイルがある場合、上書き前に確認する(interactive) |
-v | 処理内容を1件ずつ表示する(verbose) |
-p | 更新日時やパーミッションなどの属性を保持したままコピーする |
$ cp memo.txt memo-backup.txt
$ cp -r notes notes-backup
$ cp -iv *.txt backup/ # 上書き確認しながら、処理内容を表示してコピー
実機のcpは、コピー元がディレクトリのときに-rを付け忘れると「omitting directory(ディレクトリなので省略しました)」といった趣旨のエラーになり、コピーが行われません。ディレクトリを含むコピー作業をするときは、まず-rが必要かどうかを意識しましょう。ちなみに-rは「recursive(再帰的)」の略で、この章のあとに出てくるrm -rでも共通して使われる考え方です。
cpはコピー先にすでに同名のファイルがあっても、確認メッセージなしでそのまま上書きしてしまいます。大事なファイルを誤って上書きしないよう、上書きの可能性がある操作では-iオプションを付けて、確認を挟む習慣をつけると安心です。
mv — ファイルの移動・リネーム
mv は移動とリネームを兼ねています。「別のディレクトリに移す」のも「同じ場所で名前を変える」のも、内部的には同じ操作です。
| オプション | 意味 |
|---|---|
-i | 移動先に同名ファイルがある場合、上書き前に確認する |
-v | 処理内容を1件ずつ表示する |
$ mv memo2.txt notes/ # notesディレクトリへ移動
$ mv readme.txt README.txt # 名前の変更(リネーム)
「移動」と「リネーム」が同じコマンドというのは初心者には少し不思議に感じられるかもしれませんが、実は同じ操作の裏側では同じ処理(ディレクトリツリーの中でのファイルの位置を変更する)が行われています。移動先のパスの最後の要素が新しいディレクトリの中の同名ファイルなら「移動」、今いる場所での別名なら「リネーム」に見える、というだけの違いです。
cp はコピー元をそのまま残すため、操作後にディスクの使用量が増えます。一方 mv は元の場所からファイルを取り除くだけなので、基本的にディスク使用量は変わりません。「元も残したい」ならcp、「移すだけでよい」ならmvを使いましょう。
mvもコピー先に同名のファイルがあると確認なしに上書きします。特にmv a.txt b.txtのように「リネームのつもり」で実行したとき、すでにb.txtが存在すると、その内容が失われてしまいます。リネーム前にはlsで移動先の名前が使われていないか確認する習慣をつけましょう。
複数ファイルをまとめて操作する
第3章で紹介したワイルドカード(*)は、コピーや削除でも活用できます。対象を間違えると被害が大きくなるため、まずは ls で対象を確認してから操作するのが安全です。
$ ls *.txt
memo.txt readme.txt
$ cp -r *.txt backup/ # .txtファイルをまとめてbackupディレクトリへコピー
$ mv *.txt notes/ # .txtファイルをまとめてnotesディレクトリへ移動
コピー先の指定方法による違い
cpやmvのコピー先(第2引数)に何を指定するかによって、結果が変わります。
| コピー先の指定 | 結果 |
|---|---|
| 既存のディレクトリ名 | そのディレクトリの中に、元と同じファイル名でコピー・移動される。 |
| 存在しない名前 | その名前の新しいファイルとしてコピー・移動される(実質的にリネームになる)。 |
末尾に / を付けたディレクトリ名 | ディレクトリ宛てであることを明示できる。指定した名前のディレクトリが存在しない場合はエラーになる。 |
意図せずファイルが上書きされたりリネームされたりしないよう、操作前に ls でコピー先の状態を確認する習慣をつけておくと安心です。
なぜmvは一瞬で終わるのか — ファイルの正体は「inode」
大きな動画ファイルをcpでコピーすると少し時間がかかるのに、同じサイズのファイルをmvで移動すると一瞬で終わることに気づいたことはないでしょうか。これは偶然ではなく、Linuxがファイルをどう管理しているかという仕組みに理由があります。
Linuxでは、ファイルの中身(データそのもの)と、ファイル名は別々に管理されています。図書館に例えると分かりやすいかもしれません。本棚に並ぶ本そのものには、実は表紙にタイトルが書かれていなくてもよく、その代わりに「目録カード」という別の紙に、タイトルと本の保管場所(請求番号)が書かれています。私たちは目録カードでタイトルを探し、そこに書かれた番号をたよりに棚から本を取り出します。
Linuxのディレクトリは、この「目録カード」の束のようなものです。ディレクトリの中身は、実際には「ファイル名」と「inode(アイノード)番号」という管理番号の対応表にすぎません。inodeとは、ファイルの実体(データがディスクのどこに保存されているか、サイズはいくつか、パーミッションは何かといった管理情報)を持つ「本の実体そのもの」にあたります。つまりファイル名はあくまで「呼び名」であり、ファイルの正体はinode番号で管理されている、ということです。
この仕組みが分かると、mvが一瞬で終わる理由が見えてきます。同じディスク(同じファイルシステム)の中でmvを行う場合、Linuxはデータの中身を1バイトも動かしません。ディレクトリという「目録カード」の中の、名前の欄を書き換えているだけです。ファイルがどれだけ大きくても、目録カードの書き換えにかかる時間は一定なので、一瞬で終わります。一方cpは、データそのものを新しい場所にまるごと複製するため、ファイルサイズに比例して時間がかかります。
mvが一瞬で終わるのは、同じディスク(同じファイルシステム)の中で移動する場合に限られます。USBメモリなど別のストレージへmvする場合は、対応表の書き換えだけでは済まず、実際にはデータのコピー+元データの削除という処理が裏側で行われるため、ファイルサイズに応じて時間がかかります。
ファイルを消さずに整理する — シンボリックリンクとハードリンク
実機の環境では、ln -s コマンドでファイルへの「ショートカット」のようなものを作れます。これをシンボリックリンクと呼び、同じファイルを複数の場所から参照したいときに使います。ls -lで確認すると、先頭がlで始まり、リンク先のパスが矢印(->)付きで表示されるのが特徴です。ファイルを複製せずに済むため、ディスク容量を節約しつつ複数の場所から同じ内容にアクセスできます。
身近な例で言うと、Windowsの「ショートカット」やmacOSの「エイリアス」に近い機能です。設定ファイルの本体は1箇所に置いたまま、複数のバージョンのソフトウェアから同じ設定を参照させたい場合や、長いパスに短い別名を付けて操作を楽にしたい場合などによく使われます。シンボリックリンクの中身は、実際には「リンク先のパスが書かれた、別のinodeを持つ小さなファイル」です。だからこそ、リンク先の元ファイルを削除すると、シンボリックリンクだけが残り、矢印の先を失って参照エラーになります。
先ほどのinodeの仕組みが分かると、もう1種類のリンクであるハードリンク(lnを-sなしで実行して作る)も理解しやすくなります。ハードリンクは、シンボリックリンクのように「別のファイルからパスを指す」のではなく、まったく同じinode番号に、もう1つ別の名前を追加する操作です。目録カードで言えば、1冊の本に対して「タイトルA」と「タイトルB」という2枚のカードを作り、どちらも同じ請求番号を指している状態です。どちらの名前からアクセスしても、まったく同じデータにたどり着きます。
rm — ファイル・ディレクトリの削除
| オプション | 意味 |
|---|---|
-r | ディレクトリを中身ごと再帰的に削除 |
-f | 確認なしで強制的に削除(force) |
-i | 1件ずつ削除前に確認する(interactive) |
$ rm memo-backup.txt
$ rm -r notes-backup
rm にはゴミ箱がありません。削除したファイルは基本的に復元できないため、特に rm -rf はディレクトリやパスを指定し間違えると重大な被害につながります。実行前に ls で対象を確認する習慣をつけましょう。
なぜ「使用中のファイルを削除」してもプログラムは動き続けるのか
先ほど学んだ「ファイル名は目録カードにすぎず、実体はinodeにある」という仕組みは、rmの本当の動作を理解するのにも役立ちます。rmが実際に行っているのは、データそのものを即座に消し去ることではなく、ディレクトリという目録カードから、その名前のエントリを1件取り除くことです。inodeには「今、自分(このinode)が何個の名前から参照されているか」を数えるリンク数という値があり、名前が取り除かれるたびにこの数が1つ減ります。データの実体(ディスク上の領域)が実際に解放されるのは、このリンク数が0になったときです。
ここで、あるプログラムがすでにそのファイルを開いて処理中だったとしましょう。この場合、リンク数には「ディレクトリからの名前」に加えて、「プログラムが開いている」という参照も加算されています。そのため、ディレクトリから名前を消してリンク数が1つ減っても、プログラム側の参照が残っている限りリンク数は0にならず、データは消えません。名前を失った状態のまま、そのプログラムが使い終える(ファイルを閉じる)までデータは生き続け、プログラムは何事もなかったかのように動作を続けられます。ログを出力し続けるプログラムのログファイルを、稼働中のままrmで削除しても、そのプログラムがすぐにはエラーにならないのはこの仕組みのためです(中級編で扱うlogrotateというログ管理の仕組みも、この性質を利用しています)。
インターネット上でも語り草になっているミスとして、
rm -rfのあとに続くパスをスペースの入力ミスで台無しにしてしまう事故があります。たとえば「不要なディレクトリの中身を全部消したい」つもりで書いたコマンドの、パスの区切り部分に余計なスペースが入ってしまうと、意図とは全く違う場所(最悪の場合はルートディレクトリ全体)を対象にしてしまう危険があります。rm -rfを打つ前には、必ず一呼吸置いて対象のパスを見直しましょう。慣れないうちは、まずrmを付けずにlsで同じパスを指定し、消えてほしいものだけが表示されるか確認してから、lsをrm -rに置き換えるという手順がおすすめです。
削除前に確認する安全な習慣(-i オプション)
誤操作を防ぐもう1つの方法として、rm -iのように-i(interactive)オプションを付けると、1件ずつ「本当に削除しますか?」という確認が入るようになります(yで削除、nでスキップ)。慣れるまでは、複数ファイルをまとめて削除するときに-iを付ける習慣をつけておくと、うっかりミスを未然に防げます。同様にcp -iやmv -iも、上書きの直前に確認を挟んでくれます。
実務では、シェルの設定ファイル(.bashrcなど)に alias rm='rm -i' のような1行を書いておき、rmと打つだけで自動的に-iが付くようにしている人も少なくありません。これは第2章で触れた「.(ドット)から始まる隠しファイル」の実用例のひとつで、自分の作業環境を安全にカスタマイズする典型的な方法です。エイリアス(別名)の詳しい設定方法は中級編で扱います。
操作前の「予行演習」という習慣
cp・mv・rmのようにファイルを変更する操作は、一度実行すると簡単には元に戻せません。慣れないうちにおすすめしたいのは、実際に操作する前に対象をlsやechoで「予行演習」する習慣です。たとえば rm *.log を実行する前に ls *.log を打ってみて、本当に消したいファイルだけがヒットしているかを確認する、というひと手間です。この癖をつけておくと、ワイルドカードの指定を誤って想定外のファイルまで巻き込んでしまう事故を大きく減らせます。
手を動かす小課題
練習用ターミナルで、次の課題を実際に試してみましょう。答えは見出しをクリックすると表示されます。
課題1: touch practice.txtで空ファイルを作り、lsで存在を確認してみましょう。
答え: touch practice.txtのあとlsを実行すると、一覧にpractice.txtが追加されているのが確認できます。中身は空(0バイト)のファイルです。
課題2: 作ったファイルをcpでコピーしたあと、mvでリネームしてみましょう。
答え: cp practice.txt practice-copy.txtでコピーを作り、mv practice-copy.txt renamed.txtで名前を変更します。lsで毎回結果を確認しながら進めると、それぞれの操作が何をしているか実感しやすくなります。
課題3: rm -i renamed.txtで、確認つきの削除を試してみましょう。
答え: rm -i renamed.txtと入力すると、削除前に確認が入ります(yで削除、nでキャンセル)。-iを付けないrmは確認なしで即削除される点も、あわせて意識しておきましょう。
この章のまとめ
touch・cp・mv・rmの4コマンドは、ファイルを扱ううえで最も出番の多い基本コマンドです。特にcpとmvは既定で上書き確認をしない点、rmには復元手段がない点は、実務でも初心者でもよく事故につながるポイントなので、意識して身につけておきましょう。次章では、作成したファイルの「中身」を確認・検索するコマンドを扱います。