在terminal/bash脚本中将文件夹拆分为多个子文件夹



我有几个文件夹,每个文件夹都有15000到40000张照片。我希望每一个都被分成子文件夹——每个子文件夹中有2000个文件。

有什么快速的方法可以创建我在旅途中需要的每个文件夹并移动所有文件?

目前,我只能找到如何将文件夹中的前x个项目移动到预先存在的目录中。为了在包含20000个项目的文件夹上使用此。。。我需要手动创建10个文件夹,并运行该命令10次。

ls -1  |  sort -n | head -2000| xargs -i mv "{}" /folder/

我试着把它放在for循环中,但在用mkdir正确制作文件夹时遇到了问题。即使在我解决了这个问题之后,我也需要该程序只为每20个文件(新组的开始)创建一个文件夹。它想为每个文件创建一个新文件夹。

所以。。。如何轻松地将大量文件移动到每个文件夹中任意数量文件的文件夹中?

任何帮助都会非常。。。好有用的

试试这样的东西:

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

对于假人:

  1. 创建新文件:vim split_files.sh
  2. 更新dir_sizedir_name值以满足您的需求
    • 请注意,dir_name将附加一个数字
  3. 导航到所需文件夹:cd my_folder
  4. 运行脚本:sh ../split_files.sh

这个解决方案在MacOS:上对我有效

i=0; for f in *; do d=dir_$(printf %03d $((i/100+1))); mkdir -p $d; mv "$f" $d; let i++; done

它会创建子文件夹,每个子文件夹包含100个元素。

此解决方案可以处理带有空格和通配符的名称,并且可以轻松扩展以支持不那么简单的树结构。它将在工作目录的所有直接子目录中查找文件,并将它们排序到这些文件的新子目录中。新目录将命名为01等:

#!/bin/bash
maxfilesperdir=20
# loop through all top level directories:
while IFS= read -r -d $'' 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 $'' 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组合已从另一个问题中被盗。

需要注意的是,简单的globbing也可以处理各种奇怪的目录和文件名。然而,它不容易扩展到多个级别的目录。

下面的代码假设文件名不包含换行符、空格、制表符、单引号、双引号或反斜杠,并且文件名不以短划线开头。它还假设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())=}',以将编号填充为四位数字。

ls|parallel -n2000 mkdir {#};mv {} {#}

下面的命令假定文件名不包含换行符。它使用了Aristotle Pagaltzis对rename的实现,这是Homebrew中的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

上面的答案非常有用,但在Mac(10.13.6)终端中有一个非常重要的点。由于xargs"-i"参数不可用,我将命令从上面改为下面。

ls -1 | sort -n | head -2000| xargs -I '{}' mv {} /folder/

然后,我使用下面的shell脚本(参考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

这是对Mark Setchell的的调整

用法:

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

可以直接在终端中运行

i=0; 
for f in *; 
do 
    d=picture_$(printf %03d $((i/2000+1))); 
    mkdir -p $d; 
    mv "$f" $d; 
    let i++; 
done

此脚本将把当前目录中的所有文件移动到picture_001、picture_002…等等。每个新创建的文件夹将包含2000个文件

  • 2000是分块的数字
  • %03d是您可以调整的后缀数字(目前为001002003)
  • picture_是文件夹前缀
  • 此脚本将把所有文件分块到其目录中(创建子目录)

您肯定需要为此编写一个脚本。要包含在脚本中的提示:

首先计算源目录中的文件数

NBFiles=$(find . -type f -name *.jpg | wc -l)

将此计数除以2000并加1,以确定要创建的目录数

NBDIR=$(( $NBFILES / 2000 + 1 ))

最后循环浏览您的文件,并在子目录中移动它们。您必须使用两个叠瓦循环:一个用于拾取并创建目标目录,另一个用于移动此子目录中的2000个文件,然后创建下一个子目录并将下一个2000个文件移动到新的子目录,等等。

相关内容

  • 没有找到相关文章

最新更新