私はいくつかのフォルダを持っており、それぞれに15,000〜40,000枚の写真があります。これらのそれぞれをサブフォルダーに分割したいと思います-それぞれに2,000個のファイルがあります。
外出先で必要な各フォルダーを作成し、すべてのファイルを移動する、これを行う簡単な方法は何ですか?
現在、フォルダ内の最初のx個のアイテムを既存のディレクトリに移動する方法しか見つかりません。 20,000個のアイテムがあるフォルダーでこれを使用するには...手動で10個のフォルダーを作成し、コマンドを10回実行する必要があります。
ls -1 | sort -n | head -2000| xargs -i mv "{}" /folder/
Forループに入れてみましたが、mkdirで適切にフォルダーを作成するのに問題があります。それを回避した後でも、20番目のファイル(新しいグループの開始)ごとにフォルダーを作成するだけのプログラムが必要です。ファイルごとに新しいフォルダを作成したいと考えています。
では、どうすれば、多数のファイルを、それぞれの任意の数のファイルのフォルダーに簡単に移動できますか?
どんな助けでも非常に...まあ...役に立ちます!
このソリューションは、空白とワイルドカードを含む名前を処理でき、簡単に拡張して、それほど単純ではないツリー構造をサポートできます。作業ディレクトリのすべての直接サブディレクトリでファイルを検索し、それらをそれらの新しいサブディレクトリに分類します。新しいディレクトリの名前は0
、1
など:
#!/bin/bash
maxfilesperdir=20
# loop through all top level directories:
while IFS= read -r -d $'\0' topleveldir
do
# enter top level subdirectory:
cd "$topleveldir"
declare -i filecount=0 # number of moved files per dir
declare -i dircount=0 # number of subdirs created per top level dir
# loop through all files in that directory and below
while IFS= read -r -d $'\0' filename
do
# whenever file counter is 0, make a new dir:
if [ "$filecount" -eq 0 ]
then
mkdir "$dircount"
fi
# move the file into the current dir:
mv "$filename" "${dircount}/"
filecount+=1
# whenever our file counter reaches its maximum, reset it, and
# increase dir counter:
if [ "$filecount" -ge "$maxfilesperdir" ]
then
dircount+=1
filecount=0
fi
done < <(find -type f -print0)
# go back to top level:
cd ..
done < <(find -mindepth 1 -maxdepth 1 -type d -print0)
find -print0
/read
プロセス置換との組み合わせが 別の質問 から盗まれました。
単純なグロブは、あらゆる種類の奇妙なディレクトリ名とファイル名も処理できることに注意してください。ただし、複数レベルのディレクトリに簡単に拡張することはできません。
次のようなものを試してください。
for i in `seq 1 20`; do mkdir -p "folder$i"; find . -type f -maxdepth 1 | head -n 2000 | xargs -i mv "{}" "folder$i"; done
フルスクリプトバージョン:
#!/bin/bash
dir_size=2000
dir_name="folder"
n=$((`find . -maxdepth 1 -type f | wc -l`/$dir_size+1))
for i in `seq 1 $n`;
do
mkdir -p "$dir_name$i";
find . -maxdepth 1 -type f | head -n $dir_size | xargs -i mv "{}" "$dir_name$i"
done
vim split_files.sh
dir_size
とdir_name
の値を希望に合わせて更新しますdir_name
には番号が追加されることに注意してくださいcd my_folder
sh ../split_files.sh
以下のコードは、ファイル名に改行、スペース、タブ、一重引用符、二重引用符、または円記号が含まれておらず、ファイル名がダッシュで始まらないことを前提としています。また、IFS
は_while read
_の代わりに_while IFS= read
_を使用し、変数が引用符で囲まれていないため、変更されていないことも前提としています。 Zshに_setopt shwordsplit
_を追加します。
_i=1;while read l;do mkdir $i;mv $l $((i++));done< <(ls|xargs -n2000)
_
以下のコードは、ファイル名に改行が含まれておらず、ダッシュで始まらないことを前提としています。 _-n2000
_は一度に2000個の引数を取り、_{#}
_はジョブのシーケンス番号です。 _{#}
_を'{=$_=sprintf("%04d",$job->seq())=}'
に置き換えて、数字を4桁に埋め込みます。
_ls|parallel -n2000 mkdir {#}\;mv {} {#}
_
以下のコマンドは、ファイル名に改行が含まれていないことを前提としています。これは、Homebrewのrename
式であるAristotlePagaltzisによるrename
の実装を使用します。ここで、ディレクトリを作成するには_-p
_が必要であり、パスを取得するには_--stdin
_が必要です。 STDINから、ここで_$N
_はファイルの番号です。他の実装では、_$.
_の代わりに_++$::i
_または_$N
_を使用できます。
_ls|rename --stdin -p 's,^,1+int(($N-1)/2000)."/",e'
_
私はこのようなもので行きます:
#!/bin/bash
# outnum generates the name of the output directory
outnum=1
# n is the number of files we have moved
n=0
# Go through all JPG files in the current directory
for f in *.jpg; do
# Create new output directory if first of new batch of 2000
if [ $n -eq 0 ]; then
outdir=folder$outnum
mkdir $outdir
((outnum++))
fi
# Move the file to the new subdirectory
mv "$f" "$outdir"
# Count how many we have moved to there
((n++))
# Start a new output directory if we have sent 2000
[ $n -eq 2000 ] && n=0
done
この解決策 MacOSで私のために働いた:
i=0; for f in *; do d=dir_$(printf %03d $((i/100+1))); mkdir -p $d; mv "$f" $d; let i++; done
それぞれ100要素のサブフォルダーを作成します。
そのためのスクリプトを作成する必要があります。スクリプトに含めるべきことのヒント:
まず、ソースディレクトリ内のファイルの数を数えます
NBFiles=$(find . -type f -name *.jpg | wc -l)
この数を2000で割り、1を足して、作成するディレクトリの数を決定します
NBDIR=$(( $NBFILES / 2000 + 1 ))
最後に、ファイルをループして、サブディレクトリ間でファイルを移動します。 2つの暗黙のループを使用する必要があります。1つは宛先ディレクトリを選択して作成し、もう1つはこのサブディレクトリに2000ファイルを移動し、次のサブディレクトリを作成して次の2000ファイルを新しいものに移動します。
上記の答えは非常に便利ですが、Mac(10.13.6)端末には非常に重要なポイントがあります。 xargs "-i"引数が使用できないため、コマンドを上から下に変更しました。
ls -1 | sort -n | head -2000| xargs -I '{}' mv {} /folder/
次に、以下のシェルスクリプトを使用します(tmpの回答を参照)
#!/bin/bash
dir_size=500
dir_name="folder"
n=$((`find . -maxdepth 1 -type f | wc -l`/$dir_size+1))
for i in `seq 1 $n`;
do
mkdir -p "$dir_name$i";
find . -maxdepth 1 -type f | head -n $dir_size | xargs -I '{}' mv {} "$dir_name$i"
done
これはMarkSetchellの微調整です
使用法:bash splitfiles.bash $ PWD/directoryoffiles splitsize
スクリプトを分割するファイルと同じディレクトリに配置する必要はありません。スクリプトは.jpgだけでなくすべてのファイルで動作し、引数として分割サイズを指定できます。
#!/bin/bash
# outnum generates the name of the output directory
outnum=1
# n is the number of files we have moved
n=0
if [ "$#" -ne 2 ]; then
echo Wrong number of args
echo Usage: bash splitfiles.bash $PWD/directoryoffiles splitsize
exit 1
fi
# Go through all files in the specified directory
for f in $1/*; do
# Create new output directory if first of new batch
if [ $n -eq 0 ]; then
outdir=$1/$outnum
mkdir $outdir
((outnum++))
fi
# Move the file to the new subdirectory
mv "$f" "$outdir"
# Count how many we have moved to there
((n++))
# Start a new output directory if current new dir is full
[ $n -eq $2 ] && n=0
done