Tại sao -r đệ quy cần thiết khi sao chép một thư mục trong Linux?


47

Câu hỏi của tôi là tại sao bắt buộc phải sử dụng -rcờ (đệ quy) khi tạo một bản sao của một thư mục? Tức là, tại sao làm điều này:

$ cp -r dir1 copyDir1

Khi nào tôi không muốn hành vi này khi sao chép một thư mục?

Không phải là một bản sao đệ quy của một thư mục thực sự là hành vi mặc định của YouTube; hành vi chúng ta muốn gần như mọi lúc?

Cảm giác như đây là một lá cờ thừa.


Bạn có cần phải sao chép các tập tin và thư mục trong đó không?
QuyNguyen2013

Nếu bạn nghĩ rằng đây sẽ là một cải tiến, bạn có thể đăng lại yêu cầu này trên kênh nhà phát triển. Nếu không, nó có thể đã được lập trình từ lâu.
blogger

@blogger Nó đã được lập trình từ lâu, nhưng vì một lý do. Có nghĩa là nếu ai đó muốn thực hiện công việc cơ bản trong môi trường dòng lệnh, thì nhiệm vụ của họ chỉ nên dễ dàng như tránh lỗi hệ thống là khó. Có nghĩa là có lý do chính đáng một số quy ước tương tác người dùng dòng lệnh tồn tại. Tôi mở rộng về khái niệm này trong câu trả lời của tôi.
JakeGould

2
Câu hỏi này đã được hỏi và trả lời trên unix.SE .
dotancohen

Tương tự như vậy đối vớirm

Câu trả lời:


58

Cách thức hoạt động của các hệ thống tập tin, một thư mục không thực sự là một thư mục chứa các tệp mà là một thư mục là một tệp chứa các con trỏ inode để các tệp con con con được kết nối với nó. Có nghĩa, từ góc độ hệ thống tệp, tệp là tệp, nhưng thư mục chỉ là tệp chứa danh sách tệp được kết nối.

Vì vậy, từ quan điểm dòng lệnh, làm điều này:

$ cp dir1 copyDir1

Về cơ bản có nghĩa là sao chép tệp có tên, dir1vào một tệp mới có tên copyDir1. Và theo như hệ thống dir1tập tin, dù sao cũng chỉ là một tập tin; thực tế đó là một thư mục của YouTube, chỉ có thể thấy rõ khi hệ thống tập tin thực sự kiểm tra dir1xem đống bit đó thực sự là gì.

Các -rlá cờ kể về hệ thống tập tin để cuộn đệ quy xuống các tập tin / cây thư mục và sao chép bất kỳ & tất cả các nội dung mà có thể là một “đứa trẻ” của tập tin đó đến một nơi mới.

Bây giờ là lý do tại sao điều đó có vẻ thừa hoặc thừa, điều này thực sự bắt nguồn từ các phương pháp lịch sử để xử lý các hệ thống tệp. Cũng như tạo ra một hệ thống an toàn khỏi tất cả các loại lỗi liên quan đến người dùng; Vô tình cũng như cố ý.

Có nghĩa là, giả sử bạn có một ~/bintập tin trong thư mục nhà của bạn mà bạn muốn sao chép nhưng vô tình bỏ qua phần mềm ~vì bạn là một con người và mắc lỗi, vì vậy nó /bingiống như thế này:

cp /bin/ ~/copy_of_bin

Với mạng an toàn của người dùng, mạng, /binlà một thư mục kết hợp với nhu cầu -rcờ, bạn sẽ tránh vô tình sao chép toàn bộ gốc nhị phân của hệ thống mà bạn đang truy cập vào thư mục chính của mình. Nếu mạng lưới an toàn đó không tồn tại, một thảm họa nhỏ hoặc có thể là thảm họa lớn sẽ xảy ra.

Logic ở đây là trong những ngày trước, các quy ước logic / hành vi của GUI (giao diện người dùng đồ họa) cần phải được đặt để tránh việc người dùng tạo ra các rủi ro có khả năng giết chết hệ thống. Và sử dụng -rcờ bây giờ là một trong số họ.

Nếu điều đó có vẻ không cần thiết, thì không cần tìm đâu xa ngoài hệ thống GUI hiện đại, người ta có thể đặt phía trên các hệ thống tệp Linux. GUI giải quyết các vấn đề cơ bản của người dùng như thế này bằng cách cho phép một người kéo và thả các tệp và thư mục một cách dễ dàng.

Nhưng trong trường hợp của các giao diện dựa trên văn bản, rất nhiều trải nghiệm người dùng trên mạng trong thế giới đó về cơ bản chỉ là những va chạm trên đường dựa trên logic và săn bắn giúp giữ cho người dùng kiểm tra để thảm họa tiềm tàng có thể được đẩy lùi.

Tương tự, đây là lý do tại sao các hệ thống tệp Linux / Unix không có 777quyền và sudoquyền được đặt theo mặc định và cách quản trị viên hệ thống thực sự nhăn nhó khi người dùng đặt 777quyền hoặc cấp cho mọi người sudoquyền. Đây là những điều cơ bản mà người ta làm để đảm bảo hệ thống ổn định và càng chứng minh người dùng càng tốt; Bất cứ ai vội vã làm chập mạch những quy ước đó rất có thể sẽ gây ra thiệt hại cho hệ thống của họ mà không hề biết.

THÔNG TIN BỔ SUNG: Một câu trả lời khác ở đây trên trang web Unix Stack Exchange đưa ra một lời giải thích tốt về lý do tại sao một bản sao không đệ quy của một thư mục là có vấn đề; nhấn mạnh là của tôi.

Chà, không có cờ -R, chỉ có thể sao chép các tệp, vì điều bất thường là ai đó muốn sao chép một cách không đệ quy một thư mục: Một bản sao không đệ quy sẽ chỉ dẫn đến một tên thứ hai cho thư mục, chỉ vào trực tiếp cấu trúc thư mục giống nhau. Bởi vì đó hiếm khi là những gì mọi người muốn, và thực sự có một chương trình riêng biệt thực hiện điều này (ln), một bản sao thư mục không đệ quy không được phép.

Vì vậy, nếu một thư mục thực sự là một tệp có các mục inode bên trong nó, thì việc tạo một bản sao thẳng của tệp đó sẽ tương đương với cách một liên kết cứng hoạt động. Đó không phải là bất cứ ai muốn.


19
Cá nhân tôi nghĩ rằng khía cạnh "bảo vệ" của nó không vượt qua bài kiểm tra mùi. Một số người có thể dễ dàng gõ cp -r /binnhư cp-r ~/bin. Lá cờ tự nó không ngăn ngừa sai lầm hoặc nhất thiết làm cho bất cứ ai tốt hơn trong việc cẩn thận. Nếu bạn muốn ngăn ngừa lỗi, lệnh cp có thể dễ dàng nhìn vào nút đang đề cập và đưa ra lời nhắc, một cái gì đó dọc theo dòng "Đây là một thư mục, bạn có muốn sao chép tất cả nội dung vào vị trí đã chỉ định không (y /viết sai rồi)?" Đó sẽ là mạng lưới an toàn . Yêu cầu -r cho các thư mục giúp giảm mã nhiều hơn bất cứ thứ gì.
JDL

12
Tương tự xấu với hố ga. Như @JDL đã nói, cờ trong câu hỏi không làm gì để ngăn lỗi đánh máy trong đường dẫn. Tôi vui hơn khi chấp nhận sự nhất quán với các lệnh khác như một lý do, nhưng tôi có cảm giác lý do thực sự là "đó là cách nó được viết lần đầu tiên và bây giờ rất nhiều thứ dựa vào hành vi đó, thay đổi nó là không thể".
Cơ bản

7
Khi chúng ta di chuyển một thư mục chúng ta không cần -r. Tôi nghĩ rằng câu trả lời được liên kết tại unix.stackexchange.com còn hơn thế nữa. Tương đương với một bản sao không đệ quy sẽ có một thư mục thứ hai và các liên kết cứng cho tất cả các tệp bên trong cây thư mục.
gerrit

2
Nếu tôi không nhầm, -r là một phần mở rộng GNU - Tôi không nghĩ rằng cp UNIX lịch sử một bản sao đệ quy - và đó là một phần lý do của lệnh rsync .
Mei

2
@JakeGould Tôi hiểu các khái niệm cơ bản. Tuy nhiên, tôi lập luận chống lại ý kiến ​​cho rằng một cờ -r trên lệnh đang đề cập cung cấp bất kỳ sự an toàn bổ sung nào. Từ kinh nghiệm của tôi, các lệnh linux dòng lệnh về mặt lịch sử vốn không an toàn. An toàn đã được thêm giờ, nếu có. Sự an toàn vốn có trong thiết kế linux đến từ hệ thống cấp phép và cho phép chạy dưới quyền root. Không chạy như root cũng là một cái gì đó là một quy ước hơn là một thiết kế. Quy ước được hỗ trợ trong hầu hết các trình cài đặt linux mới, nhưng không phải lúc nào cũng vậy.
JDL

19

Rất đúng là đây là hành vi chúng ta muốn gần như mọi lúc. Tuy nhiên, điều này không nhất thiết có nghĩa là sao chép đệ quy nên là hành vi mặc định.

Tôi nghĩ rằng những lý do cphành động như nó có nguồn gốc từ triết lý Unix . Unix ủng hộ các chương trình làm một việc và làm tốt , cũng như các chương trình đơn giản trong cả giao diện và thực hiện (đôi khi được gọi là tệ hơn là tốt hơn ).

Mấu chốt của câu đố ở đây là nhận ra rằng cpkhông sao chép các thư mục - cpsao chép các tệp (và chỉ các tệp). Nếu bạn muốn sao chép một thư mục, hãy cp gọi chính nó theo cách đệ quy , để sao chép các tệp trên mỗi thư mục.

Tất nhiên, sự khác biệt giữa "sao chép thư mục" và "sao chép tệp đệ quy" hoàn toàn không có gì, từ quan điểm của người dùng, nhưng có giao diện này giúp việc triển khai vẫn đơn giản .

Nếu bạn đã cpcó thể sao chép các thư mục, bạn sẽ sớm muốn thêm nhiều tính năng chỉ có ý nghĩa cho các thư mục - ví dụ: bạn có thể chỉ muốn sao chép tên tệp đã kết thúc .sh. Chắc chắn, điều này dẫn đến sự phình totính năng creep mà chúng ta đã quen với các hệ điều hành khác - làm cho phần mềm chậm, phức tạp và dễ bị lỗi.

Một lợi thế khác là việc -rcũng giúp người dùng hiểu những gì đang thực sự xảy ra bên dưới giao diện. Một tác dụng phụ tuyệt vời của việc này là việc học khái niệm hoạt động đệ quy sẽ giúp bạn tiết kiệm một số công việc khi bạn tìm hiểu về các công cụ khác hỗ trợ nó (ví dụ như grep, chẳng hạn)


Một số người chắc chắn sẽ nói với bạn rằng việc tiết lộ chi tiết triển khai cho người dùng là không tốt và có nhiều tính năng hơn là tốt . Ý định của tôi ở đây chỉ đơn thuần là giải thích lý do căn bản của hành vi này, vì vậy tôi sẽ không cố gắng tranh luận bằng bất kỳ cách nào.


2
+1 Cồng kềnh làm một việc và làm tốt điều đó, cảm ơn bạn vì đã nói rõ điều này!
JakeGould

5

Tương tác với các thư mục đảm bảo bạn biết bạn đang tương tác với một thư mục và KHÔNG chỉ là một tệp.

Ví dụ:

$ 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

Vì vậy, nếu bạn muốn sao chép thành công một thư mục, vì nó ngụ ý cả thư mục và các đối tượng liên quan đến tham chiếu thư mục, bạn phải coi nó như một tập hợp các tệp:

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

3

Hậu quả của việc thay đổi mặc định sẽ là hàng ngàn tập lệnh shell sẽ bị hỏng. Điều này dẫn đến các yêu cầu POSIX và SUS cho hành vi mặc định nổi tiếng.

Lý do là sự phát triển lịch sử của các lệnh cp, ln và mv (tất cả cùng một nhị phân trên hầu hết các hệ thống UNIX cũ) trong các nhánh UNIX khác nhau. Khi -rxuất hiện (sớm cpkhông có tùy chọn sao chép thư mục; đây là trang cp đầu tiên không có -rhoặc -R), có nhiều sự khác biệt trong việc xử lý các tệp đặc biệt, liên kết tượng trưng và các phần mơ hồ khác của hệ thống tệp.

Từ Thông số kỹ thuật cơ sở nhóm mở Vấn đề 7 :

Các phiên bản trước của tiêu chuẩn này bao gồm hỗ trợ cho tùy chọn -r để sao chép phân cấp tệp. Tùy chọn -r là thông lệ lịch sử trên các hệ thống có nguồn gốc BSD và BSD. Tùy chọn này không còn được chỉ định bởi POSIX.1-2008 nhưng có thể có mặt trong một số triển khai. Tùy chọn -R đã được thêm dưới dạng từ đồng nghĩa gần với tùy chọn -r, được chọn để thống nhất với tất cả các tùy chọn khác trong tập POSIX.1-2008 này có thư mục đệ quy.

Sự khác biệt giữa -R và tùy chọn -r bị loại bỏ là trong cách xử lý bằng cp của các loại tệp khác với thư mục thông thường và thư mục. Nó được định nghĩa theo cách triển khai - tùy chọn - đã xử lý các tệp đặc biệt để cho phép cả các triển khai lịch sử và các tệp đã chọn hỗ trợ -r với các khả năng giống như -R được xác định bởi tập POSIX.1-2008 này. Cờ -r ban đầu, vì lý do lịch sử, đã không xử lý các tệp đặc biệt khác với các tệp thông thường, nhưng luôn đọc tệp và sao chép nội dung của nó. Điều này có vấn đề rõ ràng với sự hiện diện của các loại tệp đặc biệt; ví dụ: thiết bị ký tự, FIFO và ổ cắm.

Trong thực tế, bạn vẫn sẽ thấy một số người thường xuyên sử dụng:

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

Bởi vì họ không tin tưởng rằng việc cp -rthực hiện với những gì họ đã quen với một máy tùy ý; Hoặc vì họ muốn tarhành vi.


3

Nó có thể là giao diện người dùng tối ưu ngày hôm nay, nhưng đó là một quyết định được đưa ra vào khoảng năm 1970 trong quá trình thiết kế UNIX khi đĩa đắt hơn đáng kể. Hàng triệu tập lệnh shell phụ thuộc vào nó hoạt động theo cách đó và đã quá muộn để thay đổi nó.

Xem bài viết này để biết thông tin thiết kế ban đầu.


3

Một lợi thế rõ ràng của -rcờ là bạn chỉ có thể cp * /target/dirsao chép tất cả các tệp trong thư mục nguồn vào thư mục đích, bỏ qua (mặc dù có cảnh báo) tất cả các thư mục chứa trong đó. cp -r * /target/dirthay vào đó sẽ sao chép mọi thứ, kể cả thư mục con.


2

Bạn chỉ cần cờ này khi cplệnh là sao chép tệp và thư mục chứ không chỉ thư mục.

Nếu có một lệnh đặc biệt để sao chép các thư mục, thì hành vi mặc định của chế độ ăn mặc sẽ là một bản sao đệ quy.


1
Có ý nghĩa. Nhưng tại sao ai đó sẽ sao chép một thư mục không có ít nhất một tệp trong đó? Tại sao không sau đó chỉ sử dụng mkdir?
JakeGould

1
@JakeGould có lẽ vì họ có thể cần giữ quyền sở hữu và quyền?
Ruslan

1

Như những người khác đã đề cập, về cơ bản, một thư mục chỉ là một loại tệp khác (trái ngược với tệp thông thường), thường là "chứa" (trỏ đến) các tệp khác. Nó có thể chứa các thư mục con, áp dụng tương tự ...

Vì vậy, nếu bạn đang sao chép một thư mục (phối cảnh của người dùng), bạn thực sự đang sao chép một loạt các tệp (phối cảnh của hệ thống tệp) (tệp thông thường, tệp thư mục, liên kết tượng trưng, ​​...) và đối với mỗi tệp thư mục, bạn sẽ lặp lại một cách đệ quy rằng quá trình. Do việc sao chép một thư mục theo định nghĩa là một quy trình đệ quy, nên đối số của cp được gọi --recursive.

Tất nhiên, rất dễ dàng để tạo một lối tắt lệnh trong môi trường người dùng của bạn (đặt cái này vào tệp .profile / .bashrc để làm cho nó có sẵn vĩnh viễn):

alias cpr='cp -r'

Hoặc có thể tốt hơn:

alias cpa='cp -av'

Bằng cách đó, bạn có thể sao chép một thư mục bằng cách sử dụng cpa dir1 copyDir1và nó sẽ không chỉ in những gì đang được sao chép mà còn áp dụng các quyền của tệp.

Và vì ai đó đã đề cập rằng cp về mặt lý thuyết có thể phát hiện ra rằng tệp nguồn là một thư mục và hỏi liệu nó có nên sao chép nó một cách đệ quy hay không, đây là một gợi ý nhanh:

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 "$@"
}

Đây chỉ là một gói cp giá rẻ. Nó luôn bảo toàn tất cả dữ liệu meta (nghĩa là sao chép thời gian sửa đổi tệp, sao chép đúng các liên kết tượng trưng, ​​v.v.) và nếu bạn đang cố sao chép một thư mục, nó sẽ hỏi liệu nó có nên sao chép nó không (đệ quy).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.