cp cư xử kỳ lạ khi. (dấu chấm) hoặc .. (dấu chấm chấm) là thư mục nguồn


15

Câu trả lời này cho thấy rằng người ta có thể sao chép tất cả các tệp - bao gồm cả các tệp bị ẩn - từ thư mục srcvào thư mục destnhư vậy:

mkdir dest
cp -r src/. dest

Không có lời giải thích trong câu trả lời hoặc ý kiến ​​của nó về lý do tại sao điều này thực sự hoạt động, và dường như không ai tìm thấy tài liệu về điều này.

Tôi đã thử một vài điều. Đầu tiên, trường hợp bình thường:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src dest
$ ls -A dest
dest_file  src

Sau đó, với /.ở cuối:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/. dest
$ ls -A dest
dest_file  .dotfile  src_dir  src_file

Vì vậy, điều này hành xử tương tự *, nhưng cũng sao chép các tập tin ẩn.

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/* dest
$ ls -A dest
dest_file  src_dir  src_file

...là các liên kết cứng thích hợp như được giải thích ở đây , giống như mục nhập thư mục.

Hành vi này đến từ đâu và được ghi lại ở đâu?


3
Bạn có nghĩa là không ai có thể tìm thấy tài liệu? Các cptài liệu tham khảo giải thích rõ ràng làm thế nào cp -Rhoạt động. ...là những thư mục giống như bất kỳ thư mục nào khác, không có gì kỳ diệu hay bí ẩn về chúng.
AlexP

2
@AlexP Tôi đã chỉnh sửa câu trả lời để làm cho nó rõ ràng hơn. Toàn bộ vấn đề là ...không hành xử như các thư mục khác.
iFreilicht

Tôi đã cố gắng giải thích lý do tại sao nó hoạt động tại Cách sao chép một thư mục theo cách đệ quy bằng cách sử dụng cp
roaima

Câu trả lời:


27

Hành vi là một kết quả hợp lý của thuật toán tài liệu cho cp -R. Xem POSIX , bước 2f:

Các tệp trong thư mục source_file sẽ được sao chép vào thư mục Dest_file , thực hiện bốn bước (1 đến 4) được liệt kê ở đây với các tệp là source_files .

...là các thư mục, tương ứng là thư mục hiện tại và thư mục mẹ. Không có gì đặc biệt khi liên quan đến shell, vì vậy không liên quan đến việc mở rộng và thư mục sẽ được sao chép bao gồm các tệp ẩn. *mặt khác, sẽ được mở rộng thành một danh sách các tệp và đây là nơi các tệp ẩn được lọc ra.

src/.là thư mục hiện tại bên trong src, srcchính nó; src/src_dir/..src_dirthư mục mẹ, một lần nữa src. Vì vậy, từ bên ngoài src, nếu srclà một thư mục, chỉ định src/.hoặc src/src_dir/..là tệp nguồn cptương đương và sao chép nội dung của src, bao gồm các tệp ẩn.

Điểm chỉ định src/.là nó sẽ thất bại nếu srckhông phải là một thư mục (hoặc liên kết tượng trưng đến một thư mục), trong khi đó srcsẽ không. Nó cũng sẽ sao chép nội dung của srcchỉ, mà không sao chép srcchính nó; cái này cũng khớp với tài liệu này:

Nếu mục tiêu tồn tại và đặt tên cho một thư mục hiện có, tên của đường dẫn đích tương ứng cho mỗi tệp trong hệ thống phân cấp tệp sẽ là nối của mục tiêu , một ký tự gạch chéo nếu mục tiêu không kết thúc bằng dấu gạch chéo và tên đường dẫn của tệp tương đối vào thư mục chứa source_file .

Vì vậy, cp -R src/. destcác bản sao nội dung của srcđể dest/.(các tập tin nguồn .trong src), trong khi cp -R src destsao chép nội dung của srcđể dest/src(các tập tin nguồn src).

Một cách khác để nghĩ về điều này là so sánh sao chép src/src_dirsrc/., thay vì so sánh src/.src. .cư xử giống như src_dirtrong trường hợp trước.


Nhưng nó không hành xử theo cùng một cách. Chỉ định srcsẽ sao chép thư mục vào dest, src/.sẽ sao chép nội dung. Tôi sẽ cố gắng làm cho nó rõ ràng hơn trong câu hỏi.
iFreilicht

Ở đó, tôi nghĩ rằng câu trả lời cho câu hỏi cơ bản của bạn.
Stephen Kitt

1
@ Stéphane OP so sánh sao chép src/.src/*(lưu ý, không src/.* ); src/*không bao gồm các tệp ẩn nếu toàn cầu bỏ qua chúng ...
Stephen Kitt

1
Hmm, "thư mục chứa source_file ". Vâng, rõ ràng srccó chứa src/.nhưng nó có nghĩa là thư mục chứa của một thư mục phụ thuộc vào cách bạn đặt tên thư mục. Tất nhiên sự tồn tại của các .liên kết theo cách có nghĩa là tất cả các thư mục chứa chính chúng, nhưng điều đó có thể không trực quan cho tất cả. Thay vì hành vi này, người ta cũng có thể bị cho rằng "thư mục chứa thư mục foo" sẽ được xác định bởi foo/.., trong trường hợp đó sẽ không có vấn đề gì nếu chúng ta đề cập đến foohoặc foo/.: thư mục chứa kết quả sẽ giống nhau.
ilkkachu

1
Điều đó có nghĩa là sự khác biệt giữa foofoo/.có vẻ hơi tế nhị, nhưng tôi không bận tâm, tôi cũng thấy nó hơi thú vị.
ilkkachu

1

Khi bạn chạy cp -R src/foo dest, bạn sẽ nhận được dest/foo. Vì vậy, nếu thư mục dest/fookhông tồn tại, cpsẽ tạo ra nó, và sau đó sao chép nội dung của src/foođể dest/foo.

Khi bạn chạy cp -R src/. dest, cpthấy rằng dest/.tồn tại, và sau đó nó chỉ là vấn đề sao chép nội dung của src/.để dest/..

Khi bạn nghĩ về nó như sao chép một thư mục có tên .từ srcvà hợp nhất nội dung của nó với thư mục hiện có dest/., nó sẽ có ý nghĩa.

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.