Bagaimana saya bisa mengatur file berdasarkan nama file huruf pertama mereka ke dalam folder AZ

15

Saya mencari cara (lebih baik terminal) untuk mengatur lebih dari 1000 font dengan huruf pertama mereka.

Pada dasarnya buat direktori A-Z, #lalu pindahkan file font ke direktori tersebut berdasarkan karakter pertama nama filenya. Font yang dimulai dengan angka [0-9] atau karakter khusus lainnya untuk dipindahkan ke #direktori.

Parto
sumber
Apakah Anda ingin direktori dibuat bahkan jika tidak ada file yang dimulai dengan surat itu?
Arronical
@Arronical Nggak. Hanya jika ada file.
Parto
4
Saya harap tautan ini membantu Anda stackoverflow.com/questions/1251938/…
Karthickeyan

Jawaban:

13

Opsi python terlambat:

#!/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))

Cara Penggunaan

  1. Salin skrip ke file kosong, simpan sebagai move_files.py
  2. Jalankan dengan direktori sebagai argumen:

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

Script hanya akan membuat direktori (sub) (-ies) (huruf besar) jika benar-benar diperlukan

Penjelasan

Naskah:

  • daftar file, dapatkan karakter pertama (mendefinisikan sourcepath):

    for f in os.listdir(dr):
        s = f[0]; fsrc = path(dr, f)
  • memeriksa apakah item tersebut adalah file:

    if os.path.isfile(fsrc):
  • mendefinisikan folder yang ditargetkan untuk apakah char pertama adalah alpha atau tidak:

    target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
  • memeriksa apakah folder sudah ada atau tidak, buat jika tidak:

    if not os.path.exists(target):
        os.mkdir(target)
  • memindahkan item ke folder terkait:

    shutil.move(fsrc, path(target, f))
Yakub Vlijm
sumber
Hai Yakub. Apakah ada cek untuk huruf besar pertama?
Parto
@Parto Benar-Benar! Dengan cara apa Anda membutuhkannya? (Saya dapat memeriksa dalam 3,5 jam mengajar :)
Jacob Vlijm
Itu benar-benar terjadi. Implementasi sempurna.
Parto
Setelah mempertimbangkan, saya memutuskan untuk menjawab ini karena beberapa alasan: 1). Penjelasan tentang apa yang sedang terjadi. 2). Jawabannya berjalan dengan benar pada percobaan pertama
Parto
11

Code-golfed namun dapat dibaca hanya dengan dua perintah dan dua ekspresi reguler:

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

Jika Anda memiliki sejumlah besar file untuk dipindahkan, terlalu banyak untuk masuk ke dalam daftar argumen proses (ya, ada batasnya dan mungkin hanya beberapa kilobyte), Anda dapat membuat daftar file dengan perintah dan pipa yang berbeda untuk prename, misalnya:

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

Ini memiliki manfaat tambahan karena tidak mencoba untuk memindahkan nama file literal [[:alnum:]]?*jika tidak ada file yang cocok dengan pola glob. findjuga memungkinkan lebih banyak kriteria kecocokan daripada shell globbing. Alternatifnya adalah dengan mengatur nullglobopsi shell dan menutup aliran input standar prename. 1

Dalam kedua kasus, hapus -nsaklar untuk benar-benar memindahkan file dan tidak hanya menunjukkan bagaimana mereka akan dipindahkan.

Tambahan: Anda dapat menghapus direktori kosong lagi dengan:

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

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

David Foerster
sumber
8

Jika Anda tidak keberatan zsh, fungsi dan beberapa zmvperintah:

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'

The mmvFungsi membuat direktori dan bergerak file. zmvkemudian memberikan pencocokan pola dan substitusi. Pertama, memindahkan nama file dimulai dengan alfabet, lalu yang lainnya:

$ 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

Jalankan lagi tanpa echodi mmvdefinisi 's untuk benar-benar melakukan langkah itu.

muru
sumber
8

Saya tidak menemukan cara yang bagus untuk membuat nama direktori menjadi huruf besar (atau memindahkan file dengan huruf besar), meskipun Anda dapat melakukannya setelah itu dengan 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

atau lebih mudah dibaca:

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

Hapus echosetelah pengujian untuk benar-benar memindahkan file

Lalu

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

hapus -njika terlihat bagus setelah pengujian dan jalankan lagi.

Zanna
sumber
2
Anda dapat menggunakan if [[ -d "${i^}" ]]untuk membuat imodal variabel , dan mkdir {A..Z}di awal.
Arronical
Biarkan saya coba ini dan lihat
Parto
@ Terima kasihronik! Namun saya akan meninggalkannya, karena Anda mempostingnya sendiri
Zanna
@Zanna Saya suka bahwa kami datang dari arah yang berbeda, iterasi melalui surat dan menggunakannya sebagai kriteria pencarian tidak pernah terpikir oleh saya. Saya yakin ada solusi yang cerdas dan cepat dengan find, tetapi tidak bisa memahaminya!
Arronical
Hai Zanna, ini tidak memindahkan font yang dimulai dengan huruf besar. Kalau tidak bekerja dengan baik.
Parto
7

Perintah berikut dalam direktori yang berisi font harus berfungsi, jika Anda ingin menggunakan dari luar direktori penyimpanan font, ubah for f in ./*ke for f in /directory/containing/fonts/*. Ini adalah metode yang sangat berbasis shell, jadi sangat lambat, dan juga non-rekursif. Ini hanya akan membuat direktori, jika ada file yang dimulai dengan karakter yang cocok.

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

Sebagai satu liner, sekali lagi dari dalam direktori penyimpanan font:

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

Metode menggunakan find, dengan manipulasi string yang serupa, menggunakan ekspansi parameter bash, yang akan bersifat rekursif, dan harus lebih cepat daripada versi shell murni:

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' \;

Atau lebih mudah dibaca:

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' \;
Arronikal
sumber
Yang ini juga berhasil. Bahkan untuk huruf besar dan kecil.
Parto
5

Petakan setiap nama file dengan nama direktori menggunakan tr, lalu mkdirdan 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'
xn.
sumber
Saya sangat suka ini, ini sesuai dengan apa yang saya pahami dengan keinginan saya untuk menggunakan find. Apakah ada cara untuk hanya membuat nama direktori huruf besar, dan memindahkan nama file huruf kecil ke dalamnya?
Arronical
1
Saya menambahkan yang lain truntuk dikonversi ke huruf besar.
xn.
Mengapa jalan memutar xargshanya untuk menelepon bashlagi? Bukankah lebih sederhana dan lebih mudah dibaca untuk menyalurkan output findmenjadi loop sementara dan readada catatan demi catatan?
David Foerster
Pertanyaan bagus, @DavidFoerster. Saya kira bias terhadap loop dalam satu-liner dan preferensi untuk pendekatan yang lebih fungsional. Tapi skrip bash dalam sebuah string juga tidak terlalu elegan, jadi saya akan mengatakan whileversi loop ( bit.ly/2j2mhyb ) mungkin lebih baik.
xn.
By the way, Anda dapat menghindari jahat {}substitusi jika Anda membiarkan xargsappend argumen dan kemudian merujuk ke $1dalam shell script, misalnya: xargs -0 -n1 -- bash -c 'dir=/dest/$(basename "$1" | ...); ...; mv "$1" "$dir"' _. (Pikirkan yang terakhir _!)
David Foerster