cp berperilaku aneh saat. (dot) atau .. (dot dot) adalah direktori sumber

15

Jawaban ini mengungkapkan bahwa seseorang dapat menyalin semua file - termasuk yang tersembunyi - dari direktori srcke direktori destseperti:

mkdir dest
cp -r src/. dest

Tidak ada penjelasan dalam jawaban atau komentarnya tentang mengapa ini benar-benar berfungsi, dan sepertinya tidak ada yang menemukan dokumentasi mengenai hal ini juga.

Saya mencoba beberapa hal. Pertama, kasus normal:

$ 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

Kemudian, dengan /.di akhir:

$ 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

Jadi, ini berlaku secara simultan *, tetapi juga menyalin file tersembunyi.

$ 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

.dan ..merupakan tautan keras yang tepat seperti yang dijelaskan di sini , sama seperti entri direktori itu sendiri.

Dari mana perilaku ini berasal, dan dari mana itu didokumentasikan?

iFreilicht
sumber
3
Apa maksudmu tidak ada yang bisa menemukan dokumentasi? The cpreferensi jelas menjelaskan bagaimana cp -Rbekerja. .dan ..direktori sama seperti direktori lainnya, tidak ada yang magis atau misterius tentang mereka.
AlexP
2
@AlexP Saya mengedit jawaban untuk membuatnya lebih jelas. Intinya adalah itu .dan ..tidak berperilaku seperti direktori lain.
iFreilicht
Saya telah mencoba menjelaskan mengapa ia bekerja di Cara menyalin folder secara rekursif dengan cara idempoten menggunakan cp
roaima

Jawaban:

27

Perilaku adalah hasil logis dari algoritma yang didokumentasikan untuk cp -R. Lihat POSIX , langkah 2f:

File dalam direktori source_file harus disalin ke direktori dest_file , mengambil empat langkah (1 hingga 4) yang tercantum di sini dengan file sebagai source_files .

.dan ..adalah direktori, masing-masing direktori saat ini, dan direktori induk. Tidak ada yang khusus sejauh menyangkut shell, jadi tidak ada yang peduli dengan ekspansi, dan direktori akan disalin termasuk file tersembunyi. *, di sisi lain, akan diperluas ke daftar file, dan ini adalah tempat file tersembunyi disaring.

src/.adalah direktori saat ini di dalam src, yang dengan srcsendirinya; src/src_dir/..adalah src_dirdirektori induk, yang lagi src. Jadi dari luar src, apakah srcdirektori, menentukan src/.atau src/src_dir/..sebagai sumber file untuk cpsetara, dan menyalin konten src, termasuk file tersembunyi.

Maksudnya src/.adalah ia akan gagal jika srcbukan direktori (atau tautan simbolis ke direktori), sedangkan srctidak. Itu juga akan menyalin konten srcsaja, tanpa menyalin srcsendiri; ini juga cocok dengan dokumentasi:

Jika target ada dan nama direktori yang ada, nama jalur tujuan yang sesuai untuk setiap file dalam hirarki file harus merupakan gabungan dari target , karakter garis miring tunggal jika target tidak berakhir dengan garis miring, dan pathname dari file relatif ke direktori yang mengandung source_file .

Jadi cp -R src/. destmenyalin isi dari srcke dest/.(file sumber ada .di src), sedangkan cp -R src destmenyalin konten srcke dest/src(file sumber src).

Cara lain untuk memikirkan ini adalah membandingkan menyalin src/src_dirdan src/., daripada membandingkan src/.dan src. .berperilaku seperti src_dirpada kasus sebelumnya.

Stephen Kitt
sumber
Tapi itu tidak berlaku sama. Menentukan srcakan menyalin direktori ke dalam dest, src/.akan menyalin konten. Saya akan mencoba menjelaskannya dalam pertanyaan.
iFreilicht
Di sana, saya pikir itu menjawab pertanyaan mendasar Anda.
Stephen Kitt
1
@ Stéphane OP membandingkan penyalinan src/.dan src/*(catatan, bukan src/.* ); src/*tidak menyertakan file tersembunyi jika globbing mengabaikannya ...
Stephen Kitt
1
Hmm, "direktori yang mengandung source_file ". Yah, jelas srcberisi src/.tetapi itu berarti bahwa direktori yang berisi suatu direktori tergantung pada bagaimana Anda menamai direktori tersebut. Tentu saja keberadaan .tautan dengan cara itu berarti bahwa semua direktori mengandung dirinya sendiri, tetapi itu mungkin tidak intuitif untuk semua. Alih-alih perilaku ini, orang mungkin juga tergoda untuk menganggap bahwa "direktori yang berisi direktori foo" akan ditentukan oleh foo/.., dalam hal ini tidak masalah jika kita merujuk fooatau foo/.: direktori yang berisi hasilnya akan sama.
ilkkachu
1
Artinya perbedaan antara foodan foo/.tampaknya agak rumit, tapi saya tidak keberatan, saya juga merasa sedikit lucu.
ilkkachu
1

Saat Anda berlari cp -R src/foo dest, Anda akan mendapatkannya dest/foo. Jadi jika direktori dest/footidak ada, cpakan membuatnya, dan kemudian salin konten src/fooke dest/foo.

Ketika Anda menjalankan cp -R src/. dest, cpmelihat yang dest/.ada, dan hanya masalah menyalin konten src/.ke dest/..

Ketika Anda menganggapnya sebagai menyalin direktori .dari srcdan menggabungkan isinya dengan direktori yang ada dest/., itu akan masuk akal.

telcoM
sumber