Линукс:Переместите 1 миллион файлов в папки, созданные на основе префиксов.
Вопрос
У меня есть каталог «изображения», в котором хранится около миллиона изображений.Ага.
Я хочу написать команду оболочки, чтобы переименовать все эти изображения в следующий формат:
оригинал: filename.jpg
новый: /f/i/l/filename.jpg
Какие-либо предложения?
Спасибо,
Дэн
Решение
for i in *.*; do mkdir -p ${i:0:1}/${i:1:1}/${i:2:1}/; mv $i ${i:0:1}/${i:1:1}/${i:2:1}/; done;
А ${i:0:1}/${i:1:1}/${i:2:1}
часть, вероятно, может быть переменной, короче или другой, но приведенная выше команда выполняет свою работу.Вы, вероятно, столкнетесь с проблемами производительности, но если вы действительно хотите его использовать, сузьте круг *.*
меньше вариантов(a*.*
, b*.*
или что тебе подходит)
редактировать:добавил $
до i
для mv
, как заметил Дэн
Другие советы
Вы можете сгенерировать новое имя файла, используя, например, sed:
$ echo "test.jpg" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/'
t/e/s/test.jpg
Итак, вы можете сделать что-то вроде этого (при условии, что все каталоги уже созданы):
for f in *; do
mv -i "$f" "$(echo "$f" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/')"
done
или, если вы не можете использовать bash $(
синтаксис:
for f in *; do
mv -i "$f" "`echo "$f" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/'`"
done
Однако, учитывая количество файлов, вы можете просто использовать Perl, поскольку для создания большого количества процессов sed и mv:
#!/usr/bin/perl -w
use strict;
# warning: untested
opendir DIR, "." or die "opendir: $!";
my @files = readdir(DIR); # can't change dir while reading: read in advance
closedir DIR;
foreach my $f (@files) {
(my $new_name = $f) =~ s!^((.)(.)(.).*)$!$2/$3/$4/$1/;
-e $new_name and die "$new_name already exists";
rename($f, $new_name);
}
Этот Perl, безусловно, ограничен только той же файловой системой, хотя вы можете использовать File::Copy::move
чтобы обойти это.
Вы можете сделать это как bash-скрипт:
#!/bin/bash
base=base
mkdir -p $base/shorts
for n in *
do
if [ ${#n} -lt 3 ]
then
mv $n $base/shorts
else
dir=$base/${n:0:1}/${n:1:1}/${n:2:1}
mkdir -p $dir
mv $n $dir
fi
done
Излишне говорить, что вам, возможно, придется беспокоиться о пробелах и файлах с короткими именами.
Я предлагаю короткий скрипт на Python.Большинство инструментов оболочки откажутся от такого большого количества входных данных (хотя xargs может помочь).Будет обновлен пример через секунду.
#!/usr/bin/python
import os, shutil
src_dir = '/src/dir'
dest_dir = '/dest/dir'
for fn in os.listdir(src_dir):
os.makedirs(dest_dir+'/'+fn[0]+'/'+fn[1]+'/'+fn[2]+'/')
shutil.copyfile(src_dir+'/'+fn, dest_dir+'/'+fn[0]+'/'+fn[1]+'/'+fn[2]+'/'+fn)
Любое из предложенных решений, использующих в оболочке синтаксис подстановочных знаков, скорее всего, потерпит неудачу из-за огромного количества имеющихся у вас файлов.Из предлагаемых на данный момент решений Perl, вероятно, является лучшим.
Однако вы можете легко адаптировать любой из методов сценария оболочки для работы с любым количеством файлов, например:
ls -1 | \
while read filename
do
# insert the loop body of your preference here, operating on "filename"
done
Я бы по-прежнему использовал Perl, но если вы ограничены только простыми инструментами Unix, то объединение одного из приведенных выше решений оболочки с циклом, как я показал, должно помочь вам в этом.Хотя это будет медленно.