لينكس: نقل 1 مليون ملف إلى المجلدات التي تم إنشاؤها القائمة على البادئة

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

سؤال

لدي دليل يسمى "الصور" مليئة بحوالي مليون صورة. نعم.

أريد أن أكتب أمر Shell لإعادة تسمية جميع الصور في التنسيق التالي:

أصلي: 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 للحصول على ذلك.

يمكنك أن تفعل ذلك ككاتب باش:

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

وغني عن القول، قد تحتاج إلى القلق بشأن المساحات والملفات بأسماء قصيرة.

أقترح برنامج نصي قصير بيثون. معظم أدوات شل سوف تقع في ذلك بكثير من المدخلات (على الرغم من أن 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 One الأفضل.

ومع ذلك، يمكنك بسهولة تكييف أي من أساليب SHELT SCRIPT للتعامل مع أي عدد من الملفات وهكذا:

ls -1 | \
while read filename
do
  # insert the loop body of your preference here, operating on "filename"
done

ما زلت أستخدم بيرل، ولكن إذا كنت تقتصر على وجود أدوات UNIX البسيطة فقط، فإن الجمع بين إحدى حلول الشل المذكورة أعلاه مع حلقة كما أظهرت أن تحصل على هناك. سيكون بطيئا، رغم ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top