Linuxの場合:プレフィックスベース作成したフォルダの中に100万個のファイルを移動します
質問
私は約百万の画像で埋め「画像」というディレクトリがあります。うんます。
私は、次の形式にそれらの画像のすべての名前を変更するシェルコマンドを書きたいます:
元: 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
しかし、ファイルの数を考えると、あなたはちょうどそれが出現するSEDとMVプロセスの多くだとしてPerlを使用したい場合があります:
#!/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を使用しますが、あなたが唯一の私はそこにあなたを取得する必要があります示してきたようなループと上記シェルソリューションの1つを組み合わせ、その後、簡単なUNIXツールを周囲に有することに限定している場合。これは、しかし、遅くなります。