Відповіді:
Сценарій python нижче виконує цю роботу. Приховані файли зберігаються окремо у папці, а також файли без розширення.
Оскільки він може використовуватися для широкого кола цілей, я додав кілька варіантів:
exclude = ()
remove_emptyfolders = True
або False
)shutil.move(subject, new_dir+"/"+name)
автор:
shutil.copy(subject, new_dir+"/"+name)
Сценарій:
#!/usr/bin/env python3
import os
import subprocess
import shutil
# --------------------------------------------------------
reorg_dir = "/path/to/directory_to_reorganize"
exclude = (".jpg") # for example
remove_emptyfolders = True
# ---------------------------------------------------------
for root, dirs, files in os.walk(reorg_dir):
for name in files:
subject = root+"/"+name
if name.startswith("."):
extension = ".hidden_files"
elif not "." in name:
extension = ".without_extension"
else:
extension = name[name.rfind("."):]
if not extension in exclude:
new_dir = reorg_dir+"/"+extension[1:]
if not os.path.exists(new_dir):
os.mkdir(new_dir)
shutil.move(subject, new_dir+"/"+name)
def cleanup():
filelist = []
for root, dirs, files in os.walk(reorg_dir):
for name in files:
filelist.append(root+"/"+name)
directories = [item[0] for item in os.walk(reorg_dir)]
for dr in directories:
matches = [item for item in filelist if dr in item]
if len(matches) == 0:
try:
shutil.rmtree(dr)
except FileNotFoundError:
pass
if remove_emptyfolders == True:
cleanup()
ЯКЩО існує ризик небажаного перезапис дублікатів файлів
За рахунок кількох додаткових рядків ми можемо запобігти перезапису можливих дублікатів. З наведеним нижче кодом дублікати будуть перейменовані як:
duplicate_1_filename, duplicate_2_filename
тощо.
Сценарій:
#!/usr/bin/env python3
import os
import subprocess
import shutil
# --------------------------------------------------------
reorg_dir = "/path/to/directory_to_reorganize"
exclude = (".jpg") # for example
remove_emptyfolders = True
# ---------------------------------------------------------
for root, dirs, files in os.walk(reorg_dir):
for name in files:
subject = root+"/"+name
if name.startswith("."):
extension = ".hidden_files"
elif not "." in name:
extension = ".without_extension"
else:
extension = name[name.rfind("."):]
if not extension in exclude:
new_dir = reorg_dir+"/"+extension[1:]
if not os.path.exists(new_dir):
os.mkdir(new_dir)
n = 1; name_orig = name
while os.path.exists(new_dir+"/"+name):
name = "duplicate_"+str(n)+"_"+name_orig
n = n+1
newfile = new_dir+"/"+name
shutil.move(subject, newfile)
def cleanup():
filelist = []
for root, dirs, files in os.walk(reorg_dir):
for name in files:
filelist.append(root+"/"+name)
directories = [item[0] for item in os.walk(reorg_dir)]
for dr in directories:
matches = [item for item in filelist if dr in item]
if len(matches) == 0:
try:
shutil.rmtree(dr)
except FileNotFoundError:
pass
if remove_emptyfolders == True:
cleanup()
Маючи на увазі ОП, ми всі забули додати інструкцію щодо використання. Оскільки повторювані запитання можуть з’являтися ( і є ), вони можуть бути корисними.
reorganize.py
У головному розділі сценарію встановіть цільовий каталог (з файлами для реорганізації):
reorg_dir = "/path/to/directory_to_reorganize"
(використовуйте лапки, якщо каталог містить пробіли)
можливі розширення, які ви хочете виключити (напевно, жодного, як нижче):
exclude = ()
і якщо ви хочете потім видалити порожні папки:
remove_emptyfolders = True
Запустіть сценарій командою:
python3 /path/to/reorganize.py
Зверніть увагу: якщо ви хочете скопіювати файли замість переміщення , замініть:
shutil.move(subject, new_dir+"/"+name)
автор:
shutil.copy(subject, new_dir+"/"+name)
Спробуйте спочатку на невеликому зразку.
Ви можете використовувати find
дещо складну exec
команду:
find . -iname '*?.?*' -type f -exec bash -c 'EXT="${0##*.}"; mkdir -p "$PWD/${EXT}_dir"; cp --target-directory="$PWD/${EXT}_dir" "$0"' {} \;
# '*?.?*' requires at least one character before and after the '.',
# so that files like .bashrc and blah. are avoided.
# EXT="${0##*.}" - get the extension
# mkdir -p $PWD/${EXT}_dir - make the folder, ignore if it exists
Замінити cp
з echo
для сухого ходу.
Більш ефективним і акуратним було б збереження bash
команди в сценарії (скажімо, в /path/to/the/script.sh
):
#! /bin/bash
for i
do
EXT="${i##*.}"
mkdir -p "$PWD/${EXT}_dir"
mv --target-directory="$PWD/${EXT}_dir" "$i"
done
А потім запустіть find
:
find . -iname '*?.?*' -type f -exec /path/to/the/script.sh {} +
Цей підхід досить гнучкий. Наприклад, щоб використовувати ім'я файлу замість розширення ( filename.ext
), ми використовуємо це для EXT
:
NAME="${i##*/}"
EXT="${NAME%.*}"
*.fig.bak
чи .profile/.bashrc
ті, але він повинен обробляти файли лише з розширеннями, принаймні. Дякую.
ls | gawk -F. 'NF>1 {f= $NF "-DIR"; system("mkdir -p " f ";mv " $0 " " f)}'
Розрахунок списку розширень (після переміщення):
ls -d *-DIR
Розрахунок списку розширень (перед переміщенням):
ls -X | grep -Po '(?<=\.)(\w+)$'| uniq -c | sort -n
(в цьому останньому прикладі ми обчислюємо кількість файлів для кожного розширення та сортуємо його)
ls -X | grep -Po '(?<=\.)(\w+)$'
була моєю першою ідеєю отримати відсортований список розширень. Це дуже погано? Що ти пропонуєш?
ls -X
робить. Щодо того, чому я рекомендую проти ls
, дивіться unix.stackexchange.com/q/128985/70524 та unix.stackexchange.com/q/112125/70524 . Щоб досягти того, що ви робите, я б пішов довше: find . -type f -name '*?.?*' -print0 | sed -z 's/.*\.//' | sort -zu
(з необов’язком | uniq -cz
, якщо потрібні підрахунки). І find ... -print0 | gawk -v RS='\0'
(хоча це не дуже портативно ) для першого.
Спробуйте цей сценарій оболонки.
#!/bin/sh
src=`dirname "$1"`/`basename "$1"`;
for file in "$src"/*?.?*; do
if test -f "$file"; then
dest="$src${file##*.}"_files;
mkdir -p "$dest";
mv "$file" "$dest";
fi;
done;
# pass the directory to re-organize as first argument
# moves only regular files which have extension
# ignores other type of files including
# files having no extension, hidden files, directories, and links.
filepath
з file
. Я виправлю це безпосередньо.
for file in "$src"/*?.?*; do ..
read
може бути несподівана поведінка. Вам також слід цитувати змінні в командах mkdir та mv.
for i in *; do printf "%s\n" "$i"; done; for i in $(ls -d); do printf "%s\n" "$i"; done
-iname '*.*'
слід подбати про випадки кутового мене стурбовані ... хорошою ідея!