Linuxの場合:プレフィックスベース作成したフォルダの中に100万個のファイルを移動します

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*.*を狭めます

編集:ダンで述べたように、

$ためimvを追加しました

他のヒント

あなたは、例えば、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ツールを周囲に有することに限定している場合。これは、しかし、遅くなります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top