Bir klasördeki bazı dosyaları taşımak neden tüm klasörü taşımaktan daha uzun sürüyor?


21

Ubuntu bulut sunucumda milyonlarca imge var. mvKomutu kullanarak 12 milyon görüntü içeren tam bir klasörü taşıdığımda neredeyse anında oluyor. Ancak, mvyalnızca görüntüler (klasör değil) o zaman biraz zaman alır. Tüm görüntüleri klasörler kadar hızlı taşımanın bir yolu var mı?

Bu ne oluyor:

  1. src klasörü 12 milyon görüntüye sahip ve bunu kullanarak dst klasörüne taşıyorum

    $ mv  src ../dst
    

    Hemen olur

  2. Src klasörü içinde bunu taşımak için yapıyorum:

    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ {} +
    

    Bu biraz zaman alır.

İkinci süreci hızlandırmanın bir yolu var mı?


1
Bir çözüm değil - açıklığa kavuşturmak için: cmd2 daha yavaş olmalı, daha sonra cmd1 bulmalı ve sonuç için hamleyi yapmalıdır. Bu asla önceden bulma işlemi olmadan doğrudan bir hareket kadar hızlı olamaz.
dufte

Muhtemelen dstbir bölümün içinde iken ../../dst, diğerinde.
phuclv

Yazıldığı gibi, bu bile geçerli bir arama çağrısı gibi görünmüyor. {}Dosya adlarının genişletileceği herhangi bir argüman yok.
R. ..

Başlığı değiştiren, "görüntülere" yapılan referansı kaldıran ve konuyu nub ile değiştiren bir düzenleme gönderdim - tek tek dosyaları taşıyor, tüm klasörü taşıyor. Umarım bunu yapacak temsilcisi olan biri tarafından kabul edilir.
Monty Harder

1
Bu geçerli bir çağrı değil find. dosya başına bir kez find ... -exec mv -t ../../dst/ {} \;arar mv; find ... -exec mv -t ../../dest {} +arama başına olabildiğince çok sayıda dosyayı kopyalamak çok daha hızlı olurdu, ancak yine de dizinin kendisini dadexix86 tarafından açıklandığı kadar hızlı hareket etmiyordu .
chepner

Yanıtlar:


50

TL; DR : Hayır

Daha az miktarda dosya için, buna gerek findkalmaz, ancak bu basitleştirilmiş ve daha küçük davada bile,

mv *.jpg ../../dst/

bir kerede tüm dizini taşımaktan daha fazla zaman alacaktır.


Niye ya? Mesele ne olduğunu anlamak mv.

Kısacası, mvbir dizini (bir dizini veya dosyayı tanımlayan) bir inode'dan (onu içeren dizin) başka bir numaraya taşır ve bu indeksler dosya sisteminin günlüğünde veya FAT'de (dosya sistemi ise) güncellenir. böyle bir şekilde uygulanmaktadır).

Eğer kaynak ve hedef aynı dosya sisteminde ise, gerçek bir veri hareketi yoktur, sadece pozisyonu, bağlı oldukları noktayı değiştirir.

Yani, mv bir dizine girdiğinizde , bu işlemi bir kez yapıyorsunuz .

Ancak 1 milyon dosyayı taşıdığınızda , bu işlemi 1 milyon kez yapıyorsunuz .

Size pratik bir örnek vermek gerekirse, çok dallı bir ağacınız var. Özellikle, 1 milyon dalın bağlı olduğu bir düğüm vardır.
Bu dalları kesmek ve başka bir yere taşımak için, her birini kesebilir, böylece 1 milyon kesim yaparsınız veya düğümden hemen önce kesersiniz, böylece sadece bir kesim yaparsınız (bu, dosyaları taşımak arasındaki farktır. Rehber).


4
mvAynı dosya sistemindeki bir TOC girişinin sadece bir tekrarı olduğunu eklemelisiniz .
Videonauth

TOC ile ne demek istediğinizi anladığımdan emin değilim. Bildiğim kadarıyla, ext dosya sistemlerinde veya NTFS'de veya btrfs'de tablo yok. FAT'in bir adı vardır (adı aldığı) ancak örneğin ext, adları ve blokları, ebeveynleri ve çocukları ve inode'daki diğer bilgileri saklar. Eğer bana
ext'in TOC'larının

10
Um. mv *.jpg12 milyon dosya için başarısız olması muhtemeldir, bu yüzden kullandığını bulmaktadır. Çoğu Unix, Linux dahilinde (son 5-10 yıl içinde birileri değiştirmediyse) komut satırının sınırlı bir uzunluğunun olduğuna inanıyorum. Uzun zamandır Linux için 64 K olduğunu düşünüyorum. Aynı sınır çevre değişkenleri için de geçerlidir, eminim.
Zan Lynx

1
Bir dosyayı taşımak, adının taşınmasıyla ilgilidir . Unix benzeri dizin girişleri bir dosya adı ve temelde meta verilerin geri kalanına bir işaretçi olan bir inode numarası içerir. Bir dizin sadece özel bir dosya türüdür. Inode, dosyanın gerçek verilerini içermez, sadece işaretçilerden oluşur, bu nedenle bir şeyin bir inode'dan taşındığını söylemek biraz yanıltıcı olur. Öte yandan, dosya sistemi dergileri genellikle çökmeye karşı koruma için çoğunlukla kullanılan bir meta veri günlüğüne atıfta bulunur.
ilkkachu

1
Tabii ki, terminoloji burada ana nokta değildir. Önemli olan şey tam olarak söylediğiniz şey: bir dosya sistemi içinde bir hamlenin sadece meta verilere dokunması gerekiyor. Bir dosya sisteminden diğerine kısayol yoktur ve içerikleri de dahil olmak üzere tüm dosyaların birer birer taşınması (yeniden oluşturulması) gerekir. Bu durumda birinin tüm dizini taşıması ya da sadece içindeki dosyaları taşımasının bir önemi yoktur.
ilkkachu

13

Yine de yavaş olacaktır, çünkü belirtildiği gibi, dosya sistemi her bir dosya adını yeni konumuna yeniden bağlamak zorundadır.

Ancak, şimdi sahip olduklarınızdan hızlandırabilirsiniz.

Find komutunuz her dosya için bir kez exec çalıştırır. Böylece mv12 milyon dosya için 12 milyon kez komutu başlattı . Bu iki şekilde geliştirilebilir.

  • Sona artı ekleyin:
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    Sürümünüzde desteklendiğinden emin olmak için kılavuz sayfasını kontrol edin find. Etki mv, her komut satırına uyacak kadar çok dosya adı olan bir dizi komut çalıştırmak olmalıdır .

  • findVe xargsbirlikte kullanın . Dosya adları ayırmak için sıfır bayt aka NUL kullanacaktır. Bu artı , dosya adlarında boşluk olması durumunda oluşabilecek sorunları düzeltir . Komut dosya adlarının listesini okuyacak komuta ve koşmak sığacak sayıda dosya adları olarak komutu.
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    -print0xargs -0xargsxargsfindmv


7

Karışıklığınız, bir klasörün ağaç benzeri bir biçimde dosyalar ve diğer klasörler içerdiğine inanmanızı sağlayan dosya sistemi soyutlamasından gelir. Bu aslında doğru değil: bir dosya sistemindeki tüm dosyalar ve dizinler aynı seviyede bulunur ve uygulamaya bağlı olarak bir miktar sayıyla tanımlanır. Dizinler sadece diğer dosyaların listesini içeren özel dosyalardır.

Dosyaları bir dosya sisteminin içine taşıdığınızda, gerçek dosyalar hiçbir yere gitmez. Aksine, dizinlerin içindeki listeler değişikliği yansıtacak şekilde güncellenir.

mv src ../dstdizinden tek liste girdisi taşır .dizine ../dsthızlı yüzden.

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/Milyonlarca girişi taşımak zorunda, bu nedenle daha yavaş. mvDosya başına yalnızca bir kez ve bir kez arama yapmamanız potansiyel olarak hızlanabilir ve mvkomutun kendisi bir adımda birkaç dizin girişini taşımak için optimize edilmiş olabilir, ancak tek bir dizini hareket ettirdiğiniz kadar hızlı hale getirmenin bir yolu yoktur. .


4

Basitleştirilmiş bir cevap

bir dosyanın taşınması 3 adımda yapılır:

  • add () dosyaya hedef klasörün inode listesine bir link ekle
  • bağlantının başarıyla eklenip eklenmediğini kontrol edin
  • Yukarıdaki kontrol başarılı ise, () kaynak klasör düğüm listesinden verilen bağlantıyı kaldırın.

bu işlem bir dosya veya klasör için aynıdır.
ve tabii ki bunu 1 dosya için yapmak, 100 dosya için yapmaktan 100 daha hızlıdır.

man link add ()
man unlink, remove ()
mvsadece yukarıdaki iki komutu kullanır ve veri kaybını önlemek için arada bir kontrol ekler.


1
Eh, ayrıca () ismini de var.
ilkkachu
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.