2009-08-07 13 views
6

मेरे पास "छवियों" नामक एक निर्देशिका है जिसमें लगभग दस लाख छवियां हैं। हां।लिनक्स: प्रीफिक्स-आधारित बनाए गए फ़ोल्डरों में 1 मिलियन फ़ाइलों को ले जाएं

मैं निम्नलिखित प्रारूप में उन छवियों के सभी नाम बदलने के लिए एक शेल कमांड लिखना चाहते हैं:

मूल:filename.jpg
नया:/f/i/l/filename.jpg

कोई सुझाव?

धन्यवाद,
दान

+3

1 मिलियन छवियां एह? वह बहुत अश्लील है! –

उत्तर

6
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 के लिए के रूप में दान

द्वारा नोट जोड़ा,
+1

एफवाईआई, '$ {i: 0: 1} 'वाक्यविन्यास एक बैश-आईएसएम है, जो शायद ठीक है लिनक्स पर, लेकिन बस मामले में ... – derobert

+0

यदि फ़ोल्डर में कुछ निर्देशिकाएं हैं, तो क्या इस लूप में भी उन्हें शामिल किया जाएगा? – Dan

+0

में एक सुधार की आवश्यकता है: * में *। *; mkdir -p $ {i: 0: 1}/$ {i: 1: 1}/$ {i: 2: 1} /; एमवी $ i $ {i: 0: 1}/$ {i: 1: 1}/$ {i: 2: 1} /; किया हुआ; – Dan

2

आप का उपयोग कर जैसे, 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 

या, आप बैश $( सिंटैक्स का उपयोग नहीं कर सकते हैं:

for f in *; do 
    mv -i "$f" "`echo "$f" | sed -e 's/^\(\(.\)\(.\)\(.\).*\)$/\2\/\3\/\4\/\1/'`" 
done 

हालांकि, फ़ाइलों की संख्या पर विचार, तुम बस पर्ल का उपयोग करने के रूप में है कि एसईडी और 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); 
} 

पर्ल निश्चित रूप से एक ही फाइल सिस्टम तक सीमित है कि केवल , हालांकि आप इसके आसपास पाने के लिए File::Copy::move का उपयोग कर सकते हैं।

+0

उस समाधान के लिए धन्यवाद, यह एक दिलचस्प दृष्टिकोण है – Dan

+0

ओह, मुझे एक बात है कि परीक्षण मिलेगा: परीक्षण होना चाहिए "क्या यह एक फाइल है?" इसलिए यह निर्देशिका को स्थानांतरित नहीं करता है। ठीक करने के लिए काफी आसान (उदा।, '-f $ f या अगला;' पर्ल फोरैच लूप के शीर्ष पर, खोल लूप में समान) – derobert

1

मैं एक छोटी पायथन लिपि का सुझाव देता हूं। अधिकांश शैल उपकरण उस इनपुट पर बाल्क करेंगे (हालांकि 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) 
+0

धन्यवाद, एक अद्भुत समाधान की तरह दिखता है। मुझे कोशिश करने से पहले फ़ाइलों को अपने नए सर्वर में स्थानांतरित करने की प्रतीक्षा करनी होगी (ईटीए 50 घंटे लॉल) – Dan

2

आप एक 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 

जरूरत नहीं है, तो आप रिक्त स्थान और लघु नाम के साथ फ़ाइलों के बारे में चिंता करने की जरूरत हो सकती है।

+0

बहुत अच्छा समाधान, धन्यवाद – Dan

0

शैल में वाइल्डकार्ड सिंटैक्स का उपयोग करने वाले प्रस्तावित समाधानों में से कोई भी आपके पास मौजूद फाइलों की बड़ी संख्या के कारण विफल हो जाएगा। वर्तमान प्रस्तावित समाधानों में से, पर्ल एक शायद सबसे अच्छा है।

हालांकि, आप आसानी से खोल स्क्रिप्ट से किसी भी विधि अनुकूलन फ़ाइलों के किसी भी संख्या इस प्रकार से निपटने के लिए कर सकते हैं:

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

मैं अभी भी प्रयोग करेंगे पर्ल, लेकिन आप केवल सरल यूनिक्स उपकरण होने के लिए सीमित कर रहे हैं इसके आस-पास, ऊपर दिए गए शेल समाधानों में से एक को लूप के साथ संयोजित करना जैसा मैंने दिखाया है, आपको वहां ले जाना चाहिए। हालांकि, यह धीमा हो जाएगा।

+0

वाइल्डकार्ड वाक्यविन्यास ठीक होना चाहिए, इसका एक खोल अंतर्निहित है और इसे उद्देश्य पर किसी प्रोग्राम के लिए कमांड लाइन पर पारित नहीं किया जा रहा है (अन्यथा, निश्चित रूप से, कमांड लाइन बहुत लंबी होगी)। उदाहरण के लिए, 'seq 1 1000000' कार्यों में मैं काम करता हूं। – derobert

+0

मैंने अभी परीक्षण किया है: 'f f * * का उपयोग करके 1,000,000 फ़ाइलों के साथ ठीक है। धीमा, लेकिन यह काम करता है। – derobert

+0

आपकी टिप्पणी के लिए धन्यवाद, यह सहायक था क्योंकि मैं शेल स्क्रिप्टिंग – Dan