Dosyaları AZ adına ilk dosya adlarına göre nasıl düzenleyebilirim


15

İlk harfiyle 1000'den fazla yazı tipini organize etmenin bir yolunu (tercihen terminal) arıyorum.

Temel olarak dizinler oluşturun ve A-Z, #ardından dosya adlarının ilk karakterine göre yazı tipi dosyalarını bu dizinlere taşıyın. #Dizine taşınacak [0-9] sayıları veya diğer özel karakterlerle başlayan yazı tipleri .


Bu harfle başlayan dosya olmasa bile dizinlerin oluşturulmasını ister misiniz?
Arronical

@ Arronical Nope. Sadece dosyalar varsa.
Parto

4
Umarım bu bağlantı size yardımcı olur stackoverflow.com/questions/1251938/…
Karthickeyan

Yanıtlar:


13

Geç bir python seçeneği:

#!/usr/bin/env python3
import os
import sys
import shutil

def path(dr, f): return os.path.join(dr, f)

dr = sys.argv[1]
for f in os.listdir(dr):
    fsrc = path(dr, f)
    if os.path.isfile(fsrc):
        s = f[0]; target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
        if not os.path.exists(target):
            os.mkdir(target)
        shutil.move(fsrc, path(target, f))

Nasıl kullanılır

  1. Komut dosyasını boş bir dosyaya kopyalayın, move_files.py
  2. Bağımsız değişken olarak dizinle çalıştırın:

    python3 /path/to/move_files.py /path/to/files
    

Betik yalnızca (alt) dizini (-ies) (büyük harf) gerçekten gerekliyse oluşturur

açıklama

Senaryo:

  • dosyaları listeler, ilk karakteri alır (sourcepath'i tanımlar):

    for f in os.listdir(dr):
        s = f[0]; fsrc = path(dr, f)
  • öğenin bir dosya olup olmadığını kontrol eder:

    if os.path.isfile(fsrc):
  • ilk karakter alfa ise ya da değilse hedeflenen klasörü tanımlar:

    target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
  • klasörün zaten mevcut olup olmadığını kontrol eder, yoksa oluşturur:

    if not os.path.exists(target):
        os.mkdir(target)
  • öğeyi ilgili klasöre taşır:

    shutil.move(fsrc, path(target, f))

Hey Jacob. Büyük harflerin ilk harfleri için bir kontrol var mı?
Parto

@Parto Kesinlikle! Hangi yöne ihtiyacınız var? (3,5 saat öğretimde kontrol edebilirim :)
Jacob Vlijm

Aslında oldu. Mükemmel uygulama.
Parto

Düşündükten sonra, çeşitli nedenlerle bu cevaba gitmeye karar verdim: Neler olup bittiğine dair açıklama. 2). İlk denemede cevap doğru çalışıyor
Parto

11

Kod golf oynadı, ancak yalnızca iki komut ve iki normal ifade ile okunabilir:

mkdir -p '#' {a..z}
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|' [[:alnum:]]?*

Taşınacak çok fazla dosyanız varsa, işlem bağımsız değişken listesine sığmayacak kadar çok dosyanız varsa (evet, bir sınır vardır ve bu yalnızca birkaç kilobayt olabilir), farklı bir komutla dosya listesini oluşturabilir ve prename, Örneğin:

find -mindepth 1 -maxdepth 1 -name '[[:alnum:]]?*' -printf '%f\n' |
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|'

Bu, [[:alnum:]]?*glob deseniyle eşleşen dosya yoksa , gerçek dosya adını taşımaya çalışmama avantajına sahiptir . findayrıca kabuk küreciliğinden çok daha fazla eşleşme ölçütüne izin verir. Alternatif olarak, nullglobkabuk seçeneğini ayarlamak ve standart giriş akışını kapatmaktır prename. 1

Her iki durumda -nda dosyaları gerçekten taşımak için anahtarı kaldırın ve sadece nasıl taşınacaklarını göstermeyin.

Zeyilname: Boş dizinleri yeniden silebilirsiniz:

rmdir --ignore-fail-on-non-empty '#' {a..z}

1 shopt -s nullglob; prename ... <&-


8

Zsh, bir işlev ve birkaç zmvkomut sakıncası yoksa :

mmv() {echo mkdir -p "${2%/*}/"; echo mv -- "$1" "$2";}
autoload -U zmv
zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'

mmvFonksiyon dizini yapar ve dosyayı taşır. zmvdaha sonra desen eşleştirme ve değiştirme sağlar. İlk olarak, bir alfabe ile başlayan dosya adlarını, sonra her şeyi hareket ettirmek:

$ zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
mkdir -p A/
mv -- abcd.ttf A/abcd.ttf
mkdir -p A/
mv -- ABCD.ttf A/ABCD.ttf
$ zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'
mkdir -p #/
mv -- 123.ttf #/123.ttf
mkdir -p #/
mv -- 七.ttf #/七.ttf

Olmadan tekrar çalıştırın echoiçinde mmvaslında hamleyi gerçekleştirmek için bireyin tanımı.


8

Daha sonra bunu yapabilmekle birlikte, dizin adlarını büyük harf yapmak (veya büyük harflerle dosyaları taşımak) için güzel bir yol çalışmadı rename.

mkdir {a..z} \#; for i in {a..z}; do for f in "$i"*; do if [[ -f "$f" ]]; then echo mv -v -- "$f" "$i"; fi; done; done; for g in [![:alpha:]]*; do if [[ -f "$g" ]]; then echo mv -v -- "$g" \#; fi; done

veya daha okunabilir:

mkdir {a..z} \#; 
for i in {a..z}; do 
  for f in "$i"*; do
    if [[ -f "$f" ]]; then 
      echo mv -v -- "$f" "$i"; 
    fi 
  done
done
for g in [![:alpha:]]*; do 
  if [[ -f "$g" ]]; then 
    echo mv -v -- "$g" \#
  fi
done

echoDosyaları gerçekten taşımak için test ettikten sonra kaldırın

Ve sonra

rename -n 'y/[a-z]/[A-Z]/' *

-ntestten sonra iyi görünüyorsa çıkarın ve tekrar çalıştırın.


2
Sen kullanabilirsiniz if [[ -d "${i^}" ]]değişken hale getirmek için isermaye ve mkdir {A..Z}başında.
Arronical

Bunu deneyeyim ve göreyim
Parto

@ Arronical teşekkürler! Bununla birlikte, kendi yolunuza
koyduğunuz

@Zanna Ona farklı yönlerden geldiğimizi, harfleri tekrarlayarak ve arama kriteri olarak kullandığımı hiç aklıma getirmedim. Eminim bulmak için akıllı ve hızlı bir çözüm var, ama kafamı bulamıyorum!
Arronical

Hey Zanna, bu büyük harfle başlayan yazı tiplerini değiştirmedi. Aksi takdirde iyi çalıştı.
Parto

7

Eğer, yazı depolama dizini dışından kullanmak değişiklik istiyorsanız yazı tiplerini içeren dizin içinde aşağıdaki komutları çalışması gerekir for f in ./*için for f in /directory/containing/fonts/*. Bu çok kabuk tabanlı bir yöntemdir, bu yüzden oldukça yavaştır ve aynı zamanda özyinelemesizdir. Bu, yalnızca eşleşen karakterle başlayan dosyalar varsa dizinler oluşturur.

target=/directory/to/store/alphabet/dirs
mkdir "$target"
for f in ./* ; do 
  if [[ -f "$f" ]]; then 
    i=${f##*/}
    i=${i:0:1}
    dir=${i^}
    if [[ $dir != [A-Z] ]]; then 
      mkdir -p "${target}/#" && mv "$f" "${target}/#"
    else
      mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir"
    fi
  fi
done

Tek bir astar olarak, yine yazı tipi depolama dizininden:

target=/directory/to/store/alphabet/dirs; mkdir "$target" && for f in ./* ; do if [[ -f "$f" ]]; then i=${f##*/}; i=${i:0:1} ; dir=${i^} ; if [[ $dir != [A-Z] ]]; then mkdir -p "${target}/#" && mv "$f" "${target}/#"; else mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir" ; fi ; fi ; done

Yinelenen olacak ve saf kabuk sürümünden biraz daha hızlı olması gereken bash parametresi genişletmesini kullanan find, benzer dize manipülasyonu ile bir yöntem:

find . -type f -exec bash -c 'target=/directory/to/store/alphabet/dirs ; mkdir -p "$target"; f="{}" ; i="${f##*/}"; i="${i:0:1}"; i=${i^}; if [[ $i = [[:alpha:]] ]]; then mkdir -p "${target}/$i" && mv "$f" "${target}/$i"; else mkdir -p "${target}/#" && mv "$f" "${target}/#"; fi' \;

Veya daha okunaklı:

find . -type f -exec bash -c 'target=/directory/to/store/alphabet/dirs 
   mkdir -p "$target"
   f="{}"
   i="${f##*/}"
   i="${i:0:1}"
   i=${i^}
   if [[ $i = [[:alpha:]] ]]; then 
      mkdir -p "${target}/$i" && mv "$f" "${target}/$i"
   else
      mkdir -p "${target}/#" && mv "$f" "${target}/#"
   fi' \;

Bu da işe yaradı. Büyük ve küçük harfler için bile.
Parto

5

Kullanarak bir dizin adı her dosya Harita trsonra, mkdirve mv:

find /src/dir -type f -print0 |
xargs -0 -I{} bash -c \
  'dir=/dest/$(basename "{}" | cut -c1 | tr -C "a-zA-Z\n" "#" | tr "a-z "A-Z"); mkdir -p $dir; mv "{}" $dir'

Bunu gerçekten sevdim, bu benim bulma arzumla kavradığım şeyin çizgisinde. Yalnızca büyük harfli dizin adları oluşturmanın ve küçük harfli dosya adlarını bunlara taşımanın bir yolu var mı?
Arronical

1
trBüyük harfe dönüştürmek için bir tane daha ekledim .
xn.

Neden xargssadece bashtekrar aramak için dolambaçlı yoldan ? Çıktıyı findbir döngü içine sokmak daha basit ve daha okunaklı olmaz mıydı ve readorada kayıt rekoru kırdı mı?
David Foerster

Güzel soru, @DavidFoerster. Sanırım tek gömlekli döngülere karşı önyargı ve daha işlevsel bir yaklaşım tercih ediliyor. Ama bir dizede bir bash betiği de çok zarif değil, bu yüzden whiledöngü versiyonunun ( bit.ly/2j2mhyb ) belki de daha iyi olduğunu söyleyebilirim .
xn.

Bu arada, seni yaramaz önleyebilirsiniz {}izin verirsen ikame xargsargüman ekleme ve sonra bakın $1kabuk komut dosyası içinde örneğin: xargs -0 -n1 -- bash -c 'dir=/dest/$(basename "$1" | ...); ...; mv "$1" "$dir"' _. (Finali _
düşünün
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.