'Üzerine yazılan' dosyalar, hâlâ yer kaplar, kayboldular mı?


11

Aptal sabırsızlık, bir grup video dosyasını önek içeren klasörlere taşımak için 19.04 sunucumda şu komut dosyasını kullandı:

dirs=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
shopt -s nocasematch

for file in *
do
    for dir in "${dirs[@]}"
    do

     if [ -d "$file" ]; then
      echo 'this is a dir, skipping'
      break
     else
      if [[ $file =~ ^[$dir] ]]; then
       echo "----> $file moves into -> $dir <----"
       mv "$file" "$dir"
       break
      fi
     fi
  done
done

Yanlış gittiğine dair hiçbir ipucu yok, ancak dosyaları klasörlere taşımak yerine tekil bir çıktıya gitti.

----> a1.ts moves into -> A <----
----> a2.ts moves into -> A <----
----> a3.ts moves into -> A <----
----> a4.ts moves into -> A <----
----> a5.ts moves into -> A <----
----> c1.ts moves into -> C <----
----> c2.ts moves into -> C <----
----> c3.ts moves into -> C <----
----> c4.ts moves into -> C <----
----> c5.ts moves into -> C <----

Neyse ki amaçlandığı gibi gitmediğini fark etmediğim sürece tüm işlemi (CTRL + C) durdurdum ve tüm klasöre gitmedim.

Şimdi bu dosyaları aldım Ave Cbir Gb'den daha az ve görünüşe göre TEK bir video.

Klasörün kendisinin toplam disk kullanımında hesaba katılmayan 50Gb var, ancak bilgisayarın genel disk alanı aynı kaldı. Bana dosyaların silinmediğini mi düşünüyorsun?

Herhangi bir yardım takdir, teşekkürler :)

Düzenleme: dosyalar aslında gitti, sadece son dosya yazılacak kalır, tüm gereken disk kullanım bilgileri güncellemek için biraz zaman oldu .. hikayenin ahlaki, önce sahte dosyaları üzerinde komut dosyalarını çalıştırın!


3
Ve dizinleri adlı vermedi A, Bvb komut dosyasını çalıştırmadan önce var? Değilse dosyaları yeniden adlandırdınız. Adların başladığı aveya Ayeniden adlandırıldığı tüm dosyalar A, bu nedenle yalnızca en son yeniden adlandırılan dosya sağ kalmıştır, diğerlerinin üzerine yazılır. Bir değişkeni aramak dirbir dizin oluşturmaz!
mook765

2
bu şekilde de yorumladı. msgstr "son yeniden adlandırılan dosya hayatta kaldı" ha. dizinler yoktu, her el için bir 'dokunuş' eklemeliydim. açıklama için teşekkürler
Ben bir TI hesap makinesi

4
+1 için ".. hikayenin ahlaki, daha önce sahte dosyalarda komut dosyalarını çalıştırın!"
sudodus

4
Bunun gibi problemlerden kaçınmak için bir ipucu: mv "$file" "$dir/"Sondaki ile kullanın /; eğer o $diryoksa, mvbunun yerine yeniden adlandırma işleminin hatasız çalışacağını $fileiçin $dir. Ayrıca düşünün mv -ive mv -n. Ve her zaman mkdir -piyi bir önlem için, hareket etmeden önce bir yapın .
marcelm

3
@sudodus Daha iyi ahlaki, "Verilerinizi her zaman yedekleyin!".
Jon Bentley

Yanıtlar:


15

Bence bu sorun: A, B, C ... Z dizinleri oluşturmuş olmalısınız. Eğer yapmışsanız, mvkomut dosyaları bu dizinlere taşımış olmalıydı.

Ama değilse, mvkomut dosyaları A, B, C ... gibi isimlere sahip dosyalara taşır ve bence yaptığın şey budur.

Shellscript'i daha güvenli hale getirmek için, harekete başlamadan önce dizinleri (zaten orada değilse) oluşturmasını sağlamalısınız.

dirs=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)

for dir in "${dirs[@]}"
do
 mkdir -p $dir
done

Eğer daha da güvenli olsun şeyler istiyorum, ayrıca kullanabilirsiniz mvile -iseçeneği

   -i, --interactive
          prompt before overwrite

1
komut dosyası birden çok kez çalıştırılması durumunda çakışmalardan kaçınmak touchiçin iyi bir alt katkı olur mkdirmu?
Ben bir TI hesap makinesiyim

2
touchad yoksa bir dosya oluşturur. Yani bu durumda istediğini yapmayacak. mkdir -pbetiği birkaç kez kullanarak işleyebilir.
sudodus

6
Daha mvgüvenli hale getirmenin bir başka basit yolu , hedef bir dizin olduğunda hedef isme bir eğik çizgi ekleme alışkanlığına mv "$file" "$dir/"
girmektir.

7

@Sudodus neyin yanlış gittiğini zaten açıkladı , ancak bir dahaki sefere komut dosyanızın daha basit bir sürümü:

for letter in {a..z}; do 
    dir=${letter^}
    mkdir -p -- "$dir" 
    mv -- "$letter"* "${letter^^}"* "$dir"/
done

açıklama

  • for letter in {a..z}; do: ve {a..z}arasındaki tüm küçük harflere genişler :az

    $ echo {a..z}
    a b c d e f g h i j k l m n o p q r s t u v w x y z

    Böylece bu, tüm küçük harfler üzerinde yinelenerek her birini kaydeder $letter.

  • dir=${letter^}: sözdizimi , büyük harfle ilk karakteri içeren ${var^^}değişkenin içeriğini döndürür $var(çünkü bu tek bir karaktere sahiptir, tek ihtiyacımız olan şey budur). Yani, eğer $letterolduğunu a, daha sonra ${letter^^}ise Ave bu nedenle $dirakımın büyük harf versiyonu olacaktır $letter.

  • mkdir -p -- "$dir": dizini yarat. Eğer zaten varsa, hiçbir şey yapmayın ( -p). -- Seçeneklerin sonu anlamına ve ile başlayan isimlerin karşı korumak için faydalıdır -.
  • mv -- "$letter"* "${letter^}"* "$dir" : her dosyayı (veya dizini) ilgili hedefe taşımanızı sağlar.

Buradaki sorun, sahip olabileceğiniz tüm dizinleri de taşıyacağıdır. Hedef dizinleri taşımayacaktır, çünkü henüz mevcut değiller veya onları kendilerine taşımaya çalışacaksınız, ancak hedef dir olmayan varolan tüm dizinler taşınacaktır.

Bu bir sorunsa, böyle bir şey yapmanız gerekecektir:

for file in *; do 
    if [[ ! -d "$file" ]]; then 
        letter="${file:0:1}"
        dir="${letter^}"
        mkdir -p -- "$dir"
        mv -- "$file" "$dir"/
    fi
done

Arasındaki fark nedir ${letter^}ve ${letter^^}ve bunlar özdeş iseniz, neden kullanılması ${letter^^}yerine $dir?
Monica'nın Davası

1
@NicHartley ${var^}yalnızca ilk harfi ${var^^}büyük, tüm harfleri büyük yapar. Tek $letterbir harfi olduğundan burada bir fark yaratmıyor .
terdon

Eğer bir dizin çizgi ekleyerek carefulness bir kat daha eklemek isteyebilirsiniz dışında bu, mükemmel bir cevaptır $diriçinde mvkomuta. (Şu anki biçiminde, bir dosya tek harfli büyük harfle önceden varsa başarısız olur)
Stig Hemmer

@StigHemmer whoops, evet gerçekten. Çok iyi bir nokta, teşekkürler. Yanıt düzenlendi.
terdon

4

Her dosyayı bir dizi yineleme oluşturan bir sözlük dizisine karşı kontrol etmek yerine, dosyaları kalıplarla eşleştirebilirsiniz.

Çok temel sıralama:

#!/bin/bash

videos=./videos
sorted=./sorted

# sort types link,move.
sort_type=link

find "$videos" -maxdepth 1 -type f \
   \( -name '*.avi' -o -name '*.mkv' -o -name '*.mp4' \) -print0 |

while IFS= read -r -d ''; do

    b=$(basename "$REPLY")
    c=${b::1}

    case $c in
        [a-zA-Z]) label=${c^} ;; [0-9]) label="0-9" ;; *) label="_" ;;
    esac

    [[ ! -d "$sorted/$label" ]] && mkdir -p "$sorted/$label"

    if [[ -L $sorted/$label/$b ]] || [[ -e $sorted/$label/$b ]]; then
        echo "File/link: '$b' exists, skipping."
        continue
    fi

    case $sort_type in
        link)
            ln -rfst "$sorted/$label" -- "$REPLY"
            ;;
        move)
               mv -t "$sorted/$label" -- "$REPLY"
            ;;
    esac
done

Belki yanlış yaptım ama kesinlikle işe yaramadı, on dosya lol kaybetti. REPLY bölümünü anlamakta zorlanıyorum? amaç nedir Geri kalan tek şey (ABCD klasörleri .... içinde) kendilerini işaret eden takma ad dosyalarıdır .. tha takma adım
Ben TI hesap makinesiyim

REPLY, bağımsız değişken sağlanmadığında read yerleşik komutunun okuduğu giriş satırına ayarlanır.
bac0n

Tamam ve sonra sonunda ln -rfst "$ sıralanmış / $ etiket" - "$ REPLY" neden mv ile onları taşındı eğer takma ad neden?
Ben bir TI hesap makinesiyim

Varsayılan olarak, "videolar"
dizinden

... ikisi de aynı anda değil.
bac0n

2

.Bashrc dosyasında koruyun:

alias mv="mv -n --backup=numbered"

1
@Zanna, Bunun için teşekkürler! Alıntılar eklendi.

Sadece emin olmak için birkaç soru (acemi olmak), .zshrc dosyasına eklemek de geçerlidir (ZSH kullanıyorsanız)? içinde adam MV ifadesinin bulunduğundan -n Do not overwrite an existing file. (The -n option overrides any previous -f or -i options.)bu yüzden bunun bir önemi yoktur -n etiket etiketleri izlemeden önce olacak? Numaralandırılmış --backup = Her hakkın bir çift oluşturur, değil biraz overkill (ve uzay enerji / tüketen) uber-büyük video dosyaları ile uğraşan (konuşurken terabayt) olmasıdır. Teşekkürler !
Ben TI hesap makinesiyim

2

Kayıt için mvmevcut dosyaların üzerine yazmayı bırakmanın bazı yolları :

  • Bir dizine gitmek istiyorsanız, hedefe eğik çizgi ekleyin, yani mv "$file" "$dir"/yerine kullanın mv "$file" "$dir". Varsa $dirveya bir dizin değilse mv, şikayet eder:

    $ touch a
    $ mv a z/
    mv: cannot move 'a' to 'z/': Not a directory
    $ touch z
    $ mv a z/
    mv: failed to access 'z/': Not a directory

    Bu, sistem çağrısını yapıyor gibi görünmektedir rename("a", "z/"), bu nedenle, birisinin aynı dosya kümesini aynı anda işleyebilmesi durumunda, kullanım zamanı geldiğinde güvenlik açıklarından korunmalıdır.

  • Alternatif olarak, kullanın mv -t "$dir" "$file". Yine, $dirbir dizin değilse şikayet edecek .

  • -nMevcut dosyaların üzerine yazılmasını önlemek için seçeneği kullanın :

    -n, --no-clobber
        do not overwrite an existing file

    İlk dosyayı yeniden adlandırmasını engellemez, ancak başkalarıyla birlikte çöp kutusuna gönderilmez.

    Bu bir düz olarak adlandırılır rename(), bu nedenle eşzamanlı kullanımla güvenli olmayabilir. ( renameat2()Üzerine yazmayı önlemek için bir bayrağı destekleyecektir.)


1

Görünüşe göre sizin için durum böyle olmasa da, bunu yapabilmeniz ve dosyaları kaybetmemeniz mümkündür. Bu, iki şeyden birinin doğru olmasını gerektirir:

  • Dosya sisteminde başka bir yerde aynı dosyalara bir veya daha fazla 'sabit bağlantı' var
  • Bir veya daha fazla işlemin bir dosyası açık

Unix dosya sistemleri, birden fazla dizin girişinin aynı dosya içeriğine başvurmasını sağlar . Buna ' sabit bağlantı ' denir . Ortak (yumuşak / sembolik) seçenek olmadanln komutla sabit bağlantılar oluşturabilirsiniz . Dosya içeriğine en az bir sabit bağlantı bulunduğu sürece, dosya sistemi tarafından yeniden kullanılmayacaktır.-s

(Yan not, izinler genellikle dizin girdisine değil, dosya içeriğine uygulanır. Bu nedenle, sıradan bir kullanıcı bazen sahip olduğu bir dosyayı silebilir root, ancak bu dosyaya yazamaz. Silme işlemi, dosyayı değil klasörü değiştirir. )

Dosya sistemi, en az bir işlemde dosya açık olduğu sürece dosya içeriğini de yeniden kullanmayacaktır. Herhangi bir dizin girişi olmasa bile, dosya sistemi hiçbir işlem açılmadan alanın boş olduğunu düşünmez. Dosya kurtarılabilir sanal dosya sistemi /proc/<pid>/fdtarafından rootsürece dosya açık kaldığı sürece. (Teşekkürler @fluffysheap.)


1
Dosya açıkken bir işlem olursa, / proc / <pid> / fd dosyasına bakarak dosyayı kurtarabilirsiniz. Bkz. Superuser.com/questions/283102/…
fluffysheap
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.