web-dev-qa-db-ja.com

Linuxでディレクトリをコピーするときに-rが再帰的に必要なのはなぜですか?

私の質問は、なぜ-r(再帰的)フラグは、ディレクトリのコピーを作成するときですか?つまり、なぜこれを行うのですか?

$ cp -r dir1 copyDir1

ディレクトリをコピーするときにこの動作を望まないのはいつですか?

ディレクトリの再帰的なコピーは、実際には「デフォルト」の動作ではありません。ほぼ常に欲しい行動は?

これは不必要な旗のようです。

47

ファイルシステムが機能する方法、ディレクトリは実際にはファイルを含むフォルダーではなく、ディレクトリはそれに接続されている「子」ファイルへのinodeポインターを含むファイルです。つまり、ファイルシステムの観点から見ると、ファイルはファイルですが、ディレクトリは接続されたファイルのリストを含む単なるファイルです。

したがって、コマンドラインの観点からは、次のようにします。

$ cp dir1 copyDir1

基本的には、dir1という名前のファイルをcopyDir1という名前の新しいファイルにコピーします。また、ファイルシステムに関する限り、dir1はとにかく単なるファイルです。それが「ディレクトリ」であるという事実は、ファイルシステムが実際にdir1をチェックして、そのビットの山が実際に何であるかを確認するときにのみ明らかになります。

-rフラグは、ファイルシステムにファイル/ディレクトリツリーを再帰的にロールダウンし、そのファイルの「子」である可能性があるすべてのコンテンツを新しい場所にコピーするように指示します。

なぜそれが不必要または冗長に見えるかもしれないのかについては、これは本当にファイルシステムを扱う歴史的な方法に帰着します。すべてのタイプのユーザー関連エラーから安全なシステムを作成するだけでなく、偶発的だけでなく意図的。

つまり、コピーしたい~/binファイルがホームディレクトリにあり、誤って~を除外したとします。これは、あなたが人間であり、間違いを犯したためです。つまり、/binのようにこの:

cp /bin/ ~/copy_of_bin

/binの「セーフティネット」がディレクトリであり、-rフラグの必要性と組み合わせることで、現在のシステムのバイナリルート全体をホームディレクトリに誤ってコピーすることを回避できます。そのセーフティネットが存在しなかった場合、マイナー(場合によってはメジャー)の災害が発生します。

ここでのロジックは、GUIの前(グラフィカルユーザーインターフェイス)で論理/動作規則を設定して、ユーザーがシステムを強制終了する可能性のある事故を引き起こさないようにする必要があるというものです。そして、-rフラグの使用もその1つです。

それが不必要に思われる場合は、Linuxファイルシステムの上に配置できる最新のGUIシステム以外に探す必要はありません。 GUIは、ファイルやディレクトリを簡単にドラッグアンドドロップできるようにすることで、このような基本的なユーザーの問題に対処します。

しかし、テキストベースのインターフェースの領域の場合、その世界の多くの「ユーザーエクスペリエンス」は、基本的には論理的でヒューリスティックベースのロードバンプであり、ユーザーをチェックし続けることで、潜在的な災害を回避できます。

同様に、これがLinux/Unixファイルシステムにデフォルトで777権限とSudo権限が設定されていない理由であり、実際のシステム管理者がユーザーが777権限を設定したり、全員に付与したりする場合Sudo権限。これらは、システムが安定し、可能な限り「ユーザー証明」であることを保証するために行う基本的なことです。それらの慣習を短絡させようと急いでいる人はだれでもそれを知らなくても彼らのシステムに損害を与えるでしょう。

追加情報:nix Stack Exchangeサイトの別の回答 は、非再帰的なコピーの理由を説明していますディレクトリに問題があります。強調は私のものです。

まあ、-Rフラグがないと、誰かがディレクトリを非再帰的にコピーすることを望むのはかなり珍しいので、ファイルをコピーすることだけが可能です:非再帰的なコピーはただ2番目の結果になります同じディレクトリ構造を直接指すディレクトリの名前です。これはめったにないことであり、実際にはこれを行う別のプログラム(ln)があり、ディレクトリの非再帰的コピーです許可されていません。

したがって、ディレクトリが実際にその内部にiノード項目を持つファイルである場合、そのファイルの直接コピーを作成することは、ハードリンクが機能する方法と同等です。これは誰もが望んでいることではありません。

58
JakeGould

これが私たちがほぼ常に望んでいる振る舞いであることは非常に本当です。ただし、これは必ずしも再帰的なコピーがデフォルトの動作であることを意味するわけではありません。

理由cpnix哲学にルーツがあるように振る舞うと思います。 Unixは、 1つの処理を実行してうまく機能するプログラムと、両方のインターフェイスで simpleであるプログラムを優先します。と実装と呼ばれることもあります))。

ここでのパズルの重要な部分はcpはディレクトリをコピーしない-cpはファイルをコピーする(そして only ファイル)。ディレクトリをコピーする場合は、cpが自分自身を再帰的に呼び出してし、各ディレクトリにファイルをコピーします。

もちろん、「ディレクトリをコピーする」と「ファイルを再帰的にコピーする」の違いは、ユーザーの観点からはまったく何もありませんが、このインターフェースがあると、実装は単純なままです

cpがディレクトリをコピーできるようにした場合、ディレクトリにのみ意味のある機能を追加したくなるでしょう。たとえば、.shで終わるファイル名のみをコピーしたい場合があります。これは必然的に、他のオペレーティングシステムで慣れている bloat および feature creep につながり、ソフトウェアが遅く、複雑でエラーが発生しやすくなります。

もう1つの利点は、-rを使用すると、インターフェイスの下で実際に何が起こっているかをユーザーが理解しやすくなることです。これの素晴らしい副作用は、再帰的な操作の概念を学ぶことで、それをサポートする他のツール(たとえばgrepなど)について学ぶときに、ある程度の作業が不要になることです。


一部の人々は確かにユーザーに実装の詳細を公開することは bad であり、より多くの機能を持つことは good であるとあなたに言うでしょう。ここでの私の意図は、この振る舞いの理論的根拠を単に説明することなので、どちらの方法についても論じようとはしません。

19
goncalopp

ディレクトリとのやり取りにより、1つのファイルだけでなく、ディレクトリとやり取りしていることが確実になります。

例えば:

$ tree
.
└── folder1
    └── sub1
        └── subsub1

3 directories, 0 files
$
$ cp folder1/ folder2
cp: folder1/ is a directory (not copied).
$
$ mkdir blah
$ cp blah/ blah2
cp: blah/ is a directory (not copied).
$ rm blah/
rm: blah/: is a directory

したがって、フォルダーを正常にコピーする場合は、フォルダーとフォルダーの参照に関連するオブジェクトの両方を意味するため、フォルダーをファイルのコレクションのように扱う必要があります。

$ cp -r folder1/ folder2
$ rm -rf folder1
5
mbb

デフォルトを変更すると、何千ものシェルスクリプトが機能しなくなります。これは、よく知られているデフォルトの動作に対するPOSIXおよびSUS要件につながります。

その理由は、さまざまなUNIXブランチにおけるcp、ln、およびmvコマンド(ほとんどの古いUNIXシステムではすべて同じバイナリ)の歴史的な発展です。いつ -rが表示されました(初期のcpには、ディレクトリをコピーするオプションがありませんでした; これは初期のcpのマニュアルページです なし-rまたは-R)、特殊なファイル、シンボリックリンク、およびファイルシステムの他のバリエーションの処理にさまざまな違いがありました。

The Open Group Base Specifications Issue 7 から:

この標準の以前のバージョンには、ファイル階層をコピーする-rオプションのサポートが含まれていました。 -rオプションは、BSDおよびBSD由来のシステムでの歴史的な慣例です。このオプションはPOSIX.1-2008では指定されなくなりましたが、一部の実装では存在する可能性があります。 -Rオプションは-rオプションに近い同義語として追加されました。これは、POSIX.1-2008のこのボリュームの他のすべてのオプションとの一貫性を保つために選択されており、ディレクトリの再帰的な再帰を行います。

-Rと削除された-rオプションの違いは、レギュラーとディレクトリ以外のファイルタイプのcpによる処理にあります。 -オプションが特別なファイルをどのように処理して、歴史的な実装と、このボリュームのPOSIX.1-2008で定義された-Rと同じ機能を持つ-rをサポートすることを選択したファイルの両方を許可するかは、実装定義でした。オリジナルの-rフラグは、歴史的な理由により、通常のファイルとは異なる方法で特殊ファイルを処理しませんでしたが、常にファイルを読み取り、その内容をコピーしました。これには、特殊なファイルタイプが存在する場合に明らかな問題がありました。たとえば、キャラクターデバイス、FIFO、ソケットなどです。

実際には、一部の人々がまだ定期的に使用しているのを見ます。

cd dir1 ; tar -cf - . | (cd dir2 ; tar -xpf -)

彼らはそれを信用していないので、cp -r実装は、任意のマシンで慣れているものです。または、彼らはtar動作を望んでいるためです。

3
kael

今日は最適ではないUIかもしれませんが、ディスクがかなり高価なUNIXの設計中に1970年頃に決定されました。何百万ものシェルスクリプトがそのように機能することに依存しており、変更するには遅すぎます。

元の設計情報については この記事 を参照してください。

3
pjc50

-rフラグの明らかな利点は、cp * /target/dirを使用して、ソースディレクトリ内のすべてのfilesをターゲットディレクトリにコピーし、すべてのディレクトリを(警告は表示して)省略できることです。その中に含まれています。 cp -r * /target/dirは、サブディレクトリを含め、代わりにすべてをコピーします。

3
Interneci

このフラグは、cpファイルとディレクトリをコピーするためのコマンドであり、ディレクトリだけではない場合にのみ必要です。

ディレクトリのコピーのための特別なコマンドがあった場合、「デフォルト」の動作は確かに再帰的なコピーになります。

2
duDE

他の人が述べたように、ディレクトリは基本的に(通常のファイルとは対照的に)別のタイプのファイルであり、通常は他のファイルを「含む」(ポイントする)ものです。同じことが適用されるサブディレクトリを含めることができます...

したがって、ディレクトリ(ユーザーの観点)をコピーする場合、実際には一連のファイル(ファイルシステムの観点)(通常のファイル、ディレクトリファイル、シンボリックリンクなど)をコピーし、すべてのディレクトリファイルについて、それを再帰的に繰り返します。処理する。ディレクトリのコピーは定義上再帰的なプロセスであるため、cpの引数は--recursiveと呼ばれます。

もちろん、ユーザー環境でコマンドショートカットを作成するのは非常に簡単です(これを.profile/.bashrcファイルに入れて、永続的に使用できるようにします)。

alias cpr='cp -r'

または多分もっと良い:

alias cpa='cp -av'

こうすることで、cpa dir1 copyDir1を使用してディレクトリをコピーでき、コピーされた内容を印刷するだけでなく、ファイルのアクセス許可も適用します。

そして、誰かがcpが理論的にソースファイルがディレクトリであることを検出し、それを再帰的にコピーするかどうか尋ねることができると述べたので、ここに簡単な提案があります:

cp()
{
    if [ ! -e "$1" ]; then
        echo missing source file
        return 1
    fi
    arg="-d --preserve=all -v"
    if [ -d "$1" ]; then
        read -p "Copy directory recursively? " -n 1 -r
        if [ "$REPLY" == "y" ]; then
            arg="$arg -r"
        fi
        echo
    fi
    /usr/bin/cp $arg "$@"
}

これは単なる安価なcpラッパーです。常にすべてのメタデータを保持し(つまり、ファイルの変更時間をコピーし、シンボリックリンクを適切にコピーするなど)、ディレクトリをコピーしようとすると、それを(再帰的に)コピーするかどうかを尋ねます。

1
basic6