Linux'ta bir dizini kopyalarken -r neden özyineliydi?


47

Sorum şu: neden -rbir dizinin kopyasını çıkarırken (özyinelemeli) bayrağını kullanmak gerekli ? Yani, neden bunu yapalım:

$ cp -r dir1 copyDir1

Bir dizini kopyalarken bu davranışı ne zaman istemem?

Bir dizinin özyinelemeli bir kopyası gerçekten “varsayılan” davranış değildir; Neredeyse her zaman istediğimiz davranış?

Bu gereksiz bir bayrak gibi geliyor.


İçindeki dosyaları ve klasörü de kopyalamanıza gerek yok mu?
QuyNguyen2013

Bunun bir gelişme olacağını düşünüyorsanız, bu isteği geliştiriciler kanalında tekrarlayabilirsiniz. Aksi takdirde, muhtemelen uzun zaman önce programlandı.
Blogcu

@blogger Uzun zaman önce programlandı, ancak bir sebepten dolayı. Yani eğer birisi komut satırı ortamında temel işler yapmak isterse, görevleri sadece sistem arızasından kaçınmak kadar zor olmalıdır. Yani, bazı komut satırı kullanıcı etkileşimi sözleşmelerinin var olmasının iyi nedenleri var. Cevabımda bu konsepti genişletiyorum.
JakeGould


Aynı şey için de geçerlidirrm

Yanıtlar:


58

Dosya sistemlerinin çalışma şekli, bir dizin aslında dosyaları içeren bir klasör değildir, bunun yerine bir dizin ona bağlı “alt” dosyaları içeren inode işaretçiler içeren bir dosyadır . Yani, bir dosya sistemi açısından, bir dosya bir dosyadır, fakat bir dizin sadece bağlı dosyaların listesini içeren bir dosyadır.

Öyleyse, komut satırı açısından bakıldığında:

$ cp dir1 copyDir1

Temel olarak, adlandırılmış dir1dosyayı yeni bir dosyaya kopyalamak anlamına gelir copyDir1. Dosya sistemi söz konusu olduğunda, dir1yine de bir dosya; Bunun bir “dizin” olduğu gerçeği, yalnızca dosya sistemi gerçekte dir1o bit yığınının ne olduğunu görmek için kontrol ettiğinde ortaya çıkar .

-rBayrak dosya / dizin ağacının aşağı yinelemeli rulo dosya sistemini anlatır ve yeni bir yere bu dosyanın bir “çocuk” olabilecek ve tüm içeriğini kopyalamak.

Bunun neden gereksiz veya gereksiz göründüğüne gelince, bu gerçekten dosya sistemleriyle uğraşmanın tarihi yöntemlerine dayanıyor. Kullanıcı ile ilgili her türlü hatadan güvenli bir sistem oluşturmanın yanı sıra; kasten olduğu kadar kazara da olabilir.

Anlamı, hadi bir müşteriniz ~/bindışarı sol yanlışlıkla kopyalamak istiyorum ama ev dizinine ~sen -çünkü bir insan ve marka hataları-so onun sadece /binböyle:

cp /bin/ ~/copy_of_bin

Bayrağa /binduyulan ihtiyaçla birleştirilmiş bir dizin olmanın “güvenlik ağı” ile, -rbulunduğunuz sistemin bütün ikili kökünü yanlışlıkla ana dizininize kopyalamaktan kaçınacaksınız. Bu güvenlik ağı olmasaydı, küçük ya da büyük olasılıkla büyük bir felaket olur.

Buradaki mantık GUI (grafik kullanıcı arayüzleri) öncesi günlerde kullanıcının potansiyel olarak bir sistemi öldürebilecek şekilde yanlış bir şekilde yaratılmasını önlemek için mantıksal / davranışsal sözleşmelerin ayarlanması gerektiğidir. Ve -rbayrağını kullanmak şimdi onlardan biri.

Bu gereksiz görünüyorsa, Linux dosya sistemlerinin üzerine yerleştirilen modern GUI sisteminden başka bir yere bakmanıza gerek yok. Bir GUI, bunun gibi temel kullanıcı sorunlarını, dosyaları ve dizinleri kolaylıkla sürükleyip bırakma olanağı vererek giderir.

Ancak, metin tabanlı arayüzler alanında, o dünyadaki “kullanıcı deneyiminin” birçoğu, temelde, kullanıcının potansiyel olarak felaketi önleyebilmesi için kontrol altında tutmasına yardımcı olan mantıklı ve hueristik temelli yol darbeleridir.

Benzer şekilde, Linux / Unix dosya sistemlerinin varsayılan olarak belirlenen 777izin ve sudohaklara sahip olmaması ve bir kullanıcı 777izin verdiğinde veya herkesin sudohaklarını verdiğinde gerçek sistem yöneticilerinin nasıl ayrıldığının nedeni de budur . Bunlar sistemin istikrarlı ve mümkün olduğu kadar “kullanıcı kanıtı” olmasını sağlamak için yapılan temel şeylerdir; Bu sözleşmeleri kısa devre yapmak için acele eden herkes büyük olasılıkla bilmeden sistemlerine zarar verecektir.

EK BİLGİLER: Buradaki Unix Yığın Değişim sitesindeki bir başka cevap , bir dizinin özyinelemeli olmayan bir kopyasının neden sorunlu olduğu konusunda iyi bir açıklama sunar; vurgu benimdir.

Eh, -R bayrağı olmadan, sadece dosyaları kopyalamak mümkündür, çünkü birisinin bir dizini özyinelemesiz olarak kopyalamak istemesi alışılmadık bir durum değildir: Özyinelemeli olmayan bir kopya, doğrudan dizine işaret eden ikinci bir adla sonuçlanır. aynı dizin yapısı. Çünkü insanların istedikleri nadiren olur ve bunu yapan ayrı bir program vardır (ln), özyinelemeli olmayan bir dizin kopyasına izin verilmez.

Bu nedenle, bir dizin gerçekten içinde içinde inode öğeleri olan bir dosyaysa, o dosyanın düz bir kopyasını almak, bir hard linkin nasıl çalışacağına eşdeğer olacaktır. Kimsenin istediği bu değil.


19
Şahsen bunun "koruma" yönünün koku testini geçemediğini düşünüyorum. Bazı insan aynı kolaylıkla yazabilirsiniz cp -r /binolarak cp-r ~/bin. Bayrağın kendisi hataları önlemez veya bir başkasını dikkatli olmak için daha iyi hale getirir. Hataları önlemek istiyorsanız, cp komutu söz konusu düğüme kolayca bakabilir ve "Bu bir dizindir" satırları boyunca bir içerik istemi sağlayabilir. / n)?" Bu güvenlik ağı olurdu . Dizinler için -r kullanmak, kod bloğunu her şeyden daha aşağı tutar.
JDL

12
Rögar ile kötü benzetme. @JDL'nin dediği gibi, söz konusu bayrak yoldaki yazım hatasını engellemek için hiçbir şey yapmaz. Sebep olarak diğer komutlarla tutarlılığı kabul etmekten daha mutlu olurum, ancak asıl nedenin “ilk nasıl yazıldığını ve şimdi o kadar çok şeyin bu davranışa dayandığını, değiştirmenin imkansız olduğunu” hissediyorum.
Temel

7
Biz ne zaman hareket bir dizin biz do not -r gerekir. Bence unix.stackexchange.com adresindeki linkli cevap çok daha fazla. Özyinelemeli olmayan bir kopyasının eşdeğeri ikinci bir dizine ve dizin ağacındaki tüm dosyalar için sabit bağlantılara sahip olacaktır.
gerrit

2
Ben tarihsel UNIX cp düşünmüyorum - Ben, yanılmıyorsam bir GNU oldu -r vardı bir özyinelemeli kopyasını - ve bu komut için neden bir parçası rsync .
Mei

2
@JakeGould Temel kavramları anladım. Bununla birlikte, söz konusu komuttaki bir -r bayrağının herhangi bir ek güvenlik sağladığı fikrine karşı çıkarım. Tecrübelerime göre, komut satırı linux komutları tarihsel olarak doğal olarak güvensizdir. Güvenlik, eğer varsa, fazla mesai eklendi. Linux tasarımında doğasında var olan güvenlik, izin sisteminden gelir ve kök olarak kullanılmaya devam eder. Kök olarak çalışmamak aynı zamanda bir tasarımdan çok bir kongre olan bir şeydir. Kongre çoğu yeni linux yükleyicide destekleniyor, ancak her zaman desteklenmiyordu.
JDL

19

Neredeyse her zaman istediğimiz davranış olduğu çok doğru. Bu, mutlaka, özyinelemeli kopyalamanın varsayılan davranış olması gerektiği anlamına gelmez.

Sebeplerin Unix felsefesindecp kökleri olduğu gibi davrandığını düşünüyorum . Unix, bir şeyi yapan ve iyi yapan programların yanı sıra , hem arabirim hem de uygulamada basit olan programları tercih eder (bazen daha kötü olarak adlandırılır ).

Buradaki bulmacanın en önemli parçası, cpdizinleri kopyalamayacağınıncp farkına varmaktır - dosyaları kopyalar (ve sadece dosyaları). Bir dizini kopyalamak istiyorsanız , dosyaları her bir dizine kopyalamak için cp kendisini tekrar tekrar çağırır .

Elbette, "dizinleri kopyalamak" ile "dosyaları tekrar tekrar kopyalamak" arasındaki fark, kesinlikle kullanıcı açısından hiçbir şey değildir, ancak bu arayüze sahip olmak uygulamanın basit kalmasına yardımcı olur .

Eğer yaptıysanız cp, örneğin, yalnızca sona eren dosya kopyalamak isteyebilirsiniz - dizinleri kopyalamak mümkün, yakında sadece dizinleri için mantıklı daha fazla özellik eklemek için cazip olacaktır .sh. Kaçınılmaz, bu potansiyel müşteriler kabartmak ve özellik sünme diğer işletim sistemlerinde için kullanıldığını - yapma yazılımı yavaş, karmaşık ve hataya açık.

Diğer bir avantaj, -rkullanıcının arayüzün altında gerçekte ne olduğunu anlamasına yardımcı olmaktır. Bunun güzel bir yan etkisi, özyinelemeli işlem kavramını öğrenmenin, onu destekleyen diğer araçlar (örneğin grep, örneğin) hakkında bir şeyler öğrendiğinizde sizi bazı işlerden kurtarmasıdır.


Bazı insanlar size uygulama ayrıntılarını kullanıcıya göstermenin kötü olduğunu ve daha fazla özelliğe sahip olmanın iyi olduğunu kesinlikle söyleyecektir . Buradaki amacım sadece bu davranışın gerekçesini açıklamaktır, bu yüzden iki şekilde de tartışmaya çalışmıyorum.


2
+1 “… bir şey yap ve iyi yap…” Bunu belirttiğin için teşekkürler!
JakeGould

5

Dizinler ile etkileşimler, yalnızca bir dosya değil, bir dizinle etkileşime girdiğinizi bilmenizi sağlar.

Örneğin:

$ 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

Bu nedenle, bir klasörü başarılı bir şekilde kopyalamak istiyorsanız, hem klasörü hem de klasöre atıfta bulunmakla ilgili nesneleri ifade ettiğinden, onu bir dosya koleksiyonu gibi ele almanız gerekir:

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

3

Varsayılanı değiştirmenin sonucu binlerce kabuk betiğinin kırılması olacaktır. Bu, iyi bilinen varsayılan davranış için POSIX ve SUS gereksinimlerine yol açar.

Bunun nedeni, çeşitli UNIX dallarındaki cp, ln ve mv komutlarının (çoğu eski UNIX sistemindeki aynı ikili) tarihsel gelişimidir. Göründüğü zaman -r(erken cpdizinleri kopyalamak için bir seçeneğim yoktu; işte-r ya da olmadan ilk cp man sayfasıdır-R ), özel dosyalar, sembolik bağlantılar ve dosya sisteminin diğer değişkenleriyle ilgili çeşitli farklılıklar vardı.

Gönderen Açık Grubu Baz Özellikleri Issue 7 :

Bu standardın önceki sürümleri, dosya hiyerarşilerini kopyalamak için -r seçeneğinin desteğini içeriyordu. -R seçeneği BSD ve BSD'den türetilmiş sistemler üzerinde tarihsel bir uygulamadır. Bu seçenek artık POSIX.1-2008 tarafından belirtilmemiştir, ancak bazı uygulamalarda mevcut olabilir. -R seçeneği -r seçeneğine yakın bir eşanlamlı olarak eklenmiş, yinelemeli dizin inişi yapan bu POSIX.1-2008 birimindeki diğer tüm seçeneklerle tutarlılık için seçilmiştir.

-R ile kaldırılan -r seçeneği arasındaki fark normal ve dizin dışındaki dosya türlerinin cp'si ile muamele görmektir. - seçeneğinin, hem tarihsel uygulamalara hem de -r'yi desteklemeyi tercih edenlere, POSIX.1-2008'in bu cetvelinde tanımlanan -R ile aynı yeteneklere izin vermek için özel dosyalara nasıl muamele edildiği tanımlandı. Orijinal -r bayrağı, tarihi nedenlerden dolayı, özel dosyalardan normal dosyalardan farklı olarak işlem görmedi, ancak her zaman dosyayı okudu ve içeriğini kopyaladı. Bu, özel dosya türlerinin varlığında belirgin problemler yarattı; örneğin, karakter cihazları, FIFO'lar ve soketler.

Aslında, bazı kişileri düzenli olarak kullanırken hala göreceksiniz:

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

Çünkü cp -ruygulamanın keyfi bir makinede alıştıkları şey olduğuna güvenmiyorlar ; Ya da tardavranışı istedikleri için .


3

Bugün alt kullanıcı arayüzü olabilir, ancak diskin çok daha pahalı olduğu UNIX'in tasarımında 1970'li yıllarda biraz zaman alan bir karardı. Milyonlarca kabuk senaryosu bu şekilde çalışmasına bağlıdır ve değiştirmek için artık çok geç.

Orijinal tasarım bilgisi için bu makaleye bakın .


3

-rBayrağın açık bir avantajı, cp * /target/diryalnızca kaynak dizindeki tüm dosyaları hedef dizine kopyalayıp , içerdiği tüm dizinleri (bir uyarıyla da olsa) atlayabilmenizdir. cp -r * /target/diralt dizinleri de dahil olmak üzere her şeyi kopyalardı.


2

Bu bayrağa yalnızca dosya ve dizinlericp kopyalamak için bir komut olduğunda, sadece dizinleri değil, ihtiyacınız olacaktır.

Dizinlerin kopyalanması için özel bir komut varsa, “varsayılan” davranış kesinlikle tekrarlı bir kopya olacaktır.


1
Mantıklı. Fakat neden biri, içinde en az bir dosya bulunmayan bir dizini kopyalasın ki? Neden sadece kullanmıyorsun mkdir?
JakeGould

1
@JakeGould belki mülkiyeti ve izinleri korumaları gerekebileceğinden?
Ruslan

1

Diğerlerinin de belirttiği gibi, bir dizin temelde, diğer dosyaları genellikle "içeren" (işaret eder) (normal bir dosyanın aksine) sadece başka bir dosya türüdür. Aynı durumun geçerli olduğu alt dizinleri içerebilir ...

Yani bir dizini kopyalıyorsanız (kullanıcının bakış açısı), gerçekten bir sürü dosyayı (dosya sisteminin perspektifi) (normal dosyalar, dizin dosyaları, sembolik linkler, ...) kopyalıyorsunuz ve her dizin dosyası için yinelemeli olarak tekrarlıyorsunuz. süreci. Bir dizini kopyalamak tanım gereği özyinelemeli bir işlem olduğundan, cp'nin argümanı çağrılır --recursive.

Elbette, kullanıcı ortamınızda bir komut kısayolu oluşturmak çok kolaydır (bunu kalıcı olarak kullanılabilir hale getirmek için .profile / .bashrc dosyasına koyun):

alias cpr='cp -r'

Ya da belki daha iyi:

alias cpa='cp -av'

Bu şekilde, bir dizini kullanarak kopyalayabilirsiniz cpa dir1 copyDir1ve sadece kopyalananı yazdırmakla kalmaz aynı zamanda dosya izinlerini de uygular.

Ve birisi cp'nin kaynak dosyanın bir dizin olduğunu teorik olarak saptayabildiğinden ve özyinelemeyle kopyalayıp kopyalamamasını sorduğundan bahsettiğinden, işte size hızlı bir öneri:

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

Bu sadece ucuz bir cp sarıcı. Her zaman tüm meta verilerini korur (yani, dosya değiştirme zamanını kopyalar, düzgün şekilde kopyalar ve benzerlerini kopyalar) ve bir dizini kopyalamaya çalışıyorsanız, onu tekrar tekrar kopyalayıp kopyalamaması gerektiğini sorar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.