Линукс:Переместите 1 миллион файлов в папки, созданные на основе префиксов.

StackOverflow https://stackoverflow.com/questions/1242662

Вопрос

У меня есть каталог «изображения», в котором хранится около миллиона изображений.Ага.

Я хочу написать команду оболочки, чтобы переименовать все эти изображения в следующий формат:

оригинал: 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, то объединение одного из приведенных выше решений оболочки с циклом, как я показал, должно помочь вам в этом.Хотя это будет медленно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top