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


47

私の質問は-r、ディレクトリのコピーを作成するときに(再帰)フラグを使用する必要があるのはなぜですか?すなわち、なぜこれを行うのですか:

$ cp -r dir1 copyDir1

ディレクトリをコピーするときにこの動作が望ましくない場合

ディレクトリの再帰的なコピーは、実際には「デフォルト」の動作ではありません。私たちが常に望んでいる行動は?

これは余分なフラグのように感じます。


ファイルとフォルダーもコピーする必要はありませんか?
QuyNguyen2013 14年

これが改善になると思われる場合は、開発者チャンネルにこのリクエストを再投稿できます。そうでなければ、おそらくずっと前にプログラムされていました。
ブロガー

@bloggerそれはずっと前にプログラムされましたが、理由があります。誰かがコマンドライン環境で基本的な作業を行いたい場合、彼らのタスクはシステム障害を回避するのが難しいほど簡単であるべきです。つまり、いくつかのコマンドラインユーザーインタラクション規則が存在する十分な理由があります。私の答えでは、この概念を詳しく説明しています。
JakeGould


同じことがrm

回答:


58

ファイルシステムの動作方法では、ディレクトリは実際にはファイルを含むフォルダではなく、ディレクトリはそれに接続された「子」ファイルへのiノードポインタ含むファイルです。つまり、ファイルシステムの観点では、ファイルはファイルですが、ディレクトリは接続されたファイルのリストを含む単なるファイルです。

コマンドラインの観点から、これを行う:

$ 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権限を付与したときに実際のシステム管理者が勝つ方法です。これらは、システムを安定させ、可能な限り「ユーザーの証拠」とするために行う基本的なことです。それらの慣習を短絡しようと急ぐ人は、それを知らずにシステムに損害を与える可能性が高いでしょう。

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

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

したがって、ディレクトリが実際に内部にiノードアイテムを含むファイルである場合、そのファイルのストレートコピーを作成することは、ハードリンクがどのように機能するかに相当します。誰もが望んでいるものではありません。


19
個人的には、その「保護」の側面は匂いテストに合格しないと思います。一部の人間は簡単にタイプできcp -r /binましたcp-r ~/bin。フラグ自体は、間違いを防いだり、注意を払うことを必ずしも上手くしたりするものではありません。間違いを防ぎたい場合は、cpコマンドで問題のノードを簡単に確認し、「これはディレクトリです。すべてのコンテンツを指定した場所にコピーしますか? / n)?」 それセーフティネットになります。ディレクトリに-rを要求すると、コードの膨張が何よりも抑えられます。
JDL

12
マンホールとの悪い例え。@JDLが言ったように、問題のフラグはパスのタイプミスを防ぐために何もしません。私は他のコマンドとの一貫性を理由として受け入れたいと思っていますが、本当の理由は「それが最初に書かれた方法であり、今では非常に多くのものがその動作に依存しており、それを変更することは不可能です」と感じています。
基本的な

7
ディレクトリを移動するとき、-r 必要ありませ。unix.stackexchange.comのリンクされた答えは、はるかに重要だと思います。 非再帰的コピーに相当するのは、2番目のディレクトリと、ディレクトリツリー内のすべてのファイルのハードリンクです。
gerrit

2
誤解しない限り、-rはGNU拡張機能でした-歴史的なUNIX cpに再帰コピーがあったとは思われません-それがコマンドrsyncの理由の一部でした。
メイ

2
@JakeGould私は基本的な概念を理解しています。ただし、問題のコマンドに-rフラグを追加すると安全性が増すという考えに反論します。私の経験から、コマンドラインのLinuxコマンドは歴史的に本質的に安全ではありません。時間があれば、安全性が追加されました。Linuxの設計に固有の安全性は、権限システムとルートとしての実行を控えることに由来します。ルートとして実行しないことも、設計というよりも慣習です。この規則は、ほとんどの新しいLinuxインストーラーでサポートされていますが、常にそうとは限りませんでした。
JDL

19

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

Unix哲学にルーツがあるように理由はcp作用すると思う。Unixは、インターフェースと実装の両方で単純なプログラム(さらに悪いと呼ばれることが良い)だけでなく1つのことを行い、それをうまく行うプログラムを好みます。

ここでのパズルの重要な部分は、cpディレクトリをコピーしないcpこと、つまりファイル(およびファイルのみ)をコピーしないことを認識することです。ディレクトリをコピーする場合、各ディレクトリのファイルをコピーするために、cp 自分自身を再帰的呼び出します。

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

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

別の利点は-r、ユーザーがインターフェイスの下で実際に何が起こっているのかを理解するのにも役立つということです。これの良い副作用は、再帰操作の概念を学習すると、それをサポートする他のツール(grep例えば、)


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


2
+1 「…一つのことをして、うまくやれ…」これを述べてくれてありがとう!
JakeGould

5

ディレクトリとのやり取りにより、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

3

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

その理由は、さまざまなUNIXブランチでのcp、ln、およびmvコマンド(ほとんどの古いUNIXシステムではすべて同じバイナリ)の歴史的な発展です。場合には-r(早期登場cpディレクトリをコピーするオプションがありませんでした。ここでは、早期のcpのmanページがあるなし-r-R)、特殊ファイル、シンボリックリンクやファイルシステムや他の気まぐれを扱う上での様々な違いがありました。

Open Groupの基本仕様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

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

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


3

この-rフラグの明確な利点は、ソースディレクトリ内のcp * /target/dirすべてのファイルのみをターゲットディレクトリにコピーでき、そこに含まれるすべてのディレクトリを(警告はありますが)省略できることです。cp -r * /target/dir代わりに、サブディレクトリを含むすべてをコピーします。


2

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

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


1
理にかなっています。しかし、なぜ誰かが少なくとも1つのファイルを持たないディレクトリをコピーするのでしょうか?それではなぜ使用しないのmkdirですか?
JakeGould 14年

1
@JakeGouldは、所有権と権限を保持する必要があるかもしれませんか?
ルスラン

1

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

したがって、ディレクトリをコピーする場合(ユーザーの観点)、実際には多数のファイル(ファイルシステムの観点)(通常のファイル、ディレクトリファイル、シンボリックリンクなど)をコピーし、すべてのディレクトリファイルに対して、それを再帰的に繰り返します。処理する。定義上、ディレクトリのコピーは再帰的なプロセスであるため、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ラッパーです。常にすべてのメタデータを保存します(つまり、ファイルの変更時間をコピーし、シンボリックリンクを適切にコピーするなど)。ディレクトリをコピーしようとする場合、(再帰的に)コピーするかどうかを尋ねます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.