将编号文件分组到文件夹的脚本

时间:2014-11-03 17:21:19

标签: file shell unix scripting directory

我在一个文件夹中有大约一百万个文件,格式为xxxx_description.jpg,其中xxx是一个从100到未知上限的数字。

列表与此类似:

146467_description1.jpg 146467_description2.jpg 146467_description3.jpg 146467_description4.jpg 14646_description1.jpg 14646_description2.jpg 14646_description3.jpg 146472_description1.jpg 146472_description2.jpg 146472_description3.jpg 146500_description1.jpg 146500_description2.jpg 146500_description3.jpg 146500_description4.jpg 146500_description5.jpg 146500_description6.jpg

要在文件夹中记下文件编号,我想将它们全部放入按开头编号分组的文件夹中。

即: 146467/146467_description1.jpg 146467/146467_description2.jpg 146467/146467_description3.jpg 146467/146467_description4.jpg 14646/14646_description1.jpg 14646/14646_description2.jpg 14646/14646_description3.jpg 146472/146472_description1.jpg 146472/146472_description2.jpg 146472/146472_description3.jpg 146500/146500_description1.jpg 146500/146500_description2.jpg 146500/146500_description3.jpg 146500/146500_description4.jpg 146500/146500_description5.jpg 146500/146500_description6.jpg

我正在考虑尝试使用命令行:find | awk {} | mv命令或写一个脚本,但我不知道如何最有效地做到这一点。

3 个答案:

答案 0 :(得分:0)

您可以使用此脚本:

for i in [0-9]*_*.jpg; do
   p=`echo "$i" | sed 's/^\([0-9]*\)_.*/\1/'`
   mkdir -p "$p"
   mv "$i" "$p"
done

答案 1 :(得分:0)

使用grep

   for file in *.jpg; 
    do 
    dirName=$(echo $file | grep -oE '^[0-9]+')
    [[ -d $dirName ]] || mkdir $dirName
    mv $file $dirName
    done

grep -oE '^[0-9]+'将文件名中的起始数字提取为

146467
146467
146467
146467
14646
...
如果目录存在,

[[ -d $dirName ]]将返回1

[[ -d $dirName ]] || mkdir $dirName确保mkdir仅在测试[[ -d $dirName ]]失败时才起作用,即导致该导致不存在

答案 2 :(得分:0)

如果你真的在处理数百万个文件,我怀疑一个glob(*.jpg[0-9]*_*.jpg可能会失败,因为它会使shell的命令行太长。在这种情况下,您仍然可以使用find。这样的事情可能有用:

find /path -name "[0-9]*_*.jpg" -exec sh -c 'f="{}"; mkdir -p "/target/${f%_*}"; mv "$f" "/target/${f%_*}/"' \;

为便于阅读而分手,这就是我们正在做的事情:

  • find /path - 以/path为起点运行查找
  • -name "[0-9]*_*.jpg" - 匹配所有目录中与此文件规范匹配的文件
  • -exec sh -c在每个文件上执行以下操作...
    • 'f="{}"; - 将文件名放入变量......
    • mkdir -p "/target/${f%_*}"; - 根据该变量创建目标目录(阅读mkdir关于-p选项的手册页)
    • mv "$f" "/target/${f%_*}/"' - 将文件移至目录。
    • \; - 结束-exec表达式

从好的方面来说,它可以处理find可以处理的任意数量的文件(即仅受操作系统限制)。在不利方面,它为每个要处理的文件启动一个单独的shell。

请注意,上述答案适用于Bourne / POSIX / Bash 。如果您使用CSH或TCSH作为shell,则可能会出现以下情况:

#!/bin/tcsh

foreach f (*_*.jpg)
  set split = ($f:as/_/ /)
  mkdir -p "$split[1]"
  mv "$f" "$split[1]/"
end

这假设filespec适合tcsh的glob缓冲区。我在一个命令行上测试了40000个文件(894KB),并且在FreeBSD中使用/ bin / sh或/ bin / csh没有问题。 就像上面的Bourne / POSIX / Bash参数扩展解决方案一样,这可以避免不必要的外部调用我没有测试过,并且即使速度较慢也会推荐find解决方案。