创建按顺序编号的目标目录和批量移动文件的命令

创建按顺序编号的目标目录和批量移动文件的命令

我正在制作缩时视频,方法是将视频分割成单个图像,通过命令行使用 G'MIC 每 7 帧取平均值,然后将结果输出到新图像中,这些新图像将生成缩时视频的帧(这样我就可以获得无噪音的优质视频)。你可以想象我有很多帧 - 目录中有几千张单独的图像,按顺序命名(图像 1.tiff、图像 2.tiff 等。)我找到了一个可以完美移动文件的脚本——一次……

k=1; find source/ -type f | while read file; do
     [[ k++ -le 7 ]] && mv "$file" target/ 
done 

我现在需要的是制作这个脚本

  1. 重复此过程,直到所有文件都移动完毕,
  2. 创建按顺序编号的目标目录(1、2、3 等),最终得到数百个目录,每个目录包含 7 个图像。

需要澄清的是,目录 1 应该包含图像 1-7,目录 2 应该包含图像 8-14,等等。

非常感谢您的帮助,我几乎被这个困住了。

答案1

下面的(python)脚本创建子文件夹并将文件组织到文件夹中:

此外:

  • 该脚本计算文件夹的数量,并在文件夹名称中添加前导零,以便进行正确的排序(因为您提到了数千个文件,这意味着数百个文件夹)
  • 每个文件夹的文件数量可能会有所不同,具体取决于您在脚本头部的设置

该脚本假设:

  • 所有文件都有扩展名,所有文件都有相同扩大
  • 您的文件名为image1.tiffimage2.tiff等等(没有前导零)。

剧本

#!/usr/bin/env python3
import os
import math
import shutil
#---
directory = "/path/to/files"      # path to your files
n_perfolder = 7                   # number of files per sub folder
#--
# creating file list, extension
f_list = os.listdir(directory); ext = f_list[0].split(".")[-1]
# calculate number of folders
n_folders = math.ceil(len(f_list)/n_perfolder)
# creating folder names, including leading zeros
folders = [str(fn+1) for fn in range(n_folders)]
fl_names = [(len(max(folders, key=len))-len(fl))*"0"+fl for fl in folders]
# creating folders and allocate files 
for i in range(len(fl_names)):
    mkfolder = directory+"/"+fl_names[i]
    if not os.path.exists(mkfolder):
        os.makedirs(mkfolder)
        r = range(i*n_perfolder+1, i*n_perfolder+n_perfolder+1)
        for n in r:
            try:
                file = directory+"/"+"image"+str(n)+"."+ext
                target = mkfolder+"/"+"image"+str(n)+"."+ext
                shutil.copyfile(file, target)
            except FileNotFoundError:
                pass

如何使用

将脚本复制到一个空文件中,在头部部分,将目录设置为您的文件以及每个子目录的文件数,将其保存为organize.py

通过命令运行:

python3 /path/to/organize.py

笔记

如果你想移动文件而不是复制,替换以下行:

shutil.copyfile(file, target)

经过:

shutil.move(file, target)

(注意缩进!)

答案2

sevenfile=0
newdir=1
for file in "$(ls -bv /path/to/source/image*.tiff)"; do
    mkdir -p "$newdir" && mv "$file" "$newdir" 
    [[ ++sevenfile -eq 7 ]] && sevenfile=0 &&  ((newdir++))
done
  • ls -v命令按自然排序(版本)数字对文件进行排序。
    您可以ls根据自己的情况解析该命令,因为所有文件都是特定的,并且只有image*.tiff

  • mkdir -p $newdirnewdir根据变量创建目录。

  • mv "$file" "$newdir"将文件移动到newdir指定目录。

  • sevenfile=0当已移动 7 个文件时,将重置为零( [[ ++sevenfile -eq 7 ]])并增加newdir值。

请注意更改/path/to/source/为您的实际源目录。

如果您不想解析ls命令并且文件名包含空格、换行符等:

find /path/to/source/ -type f -name 'image*.tiff' -print0 | \
     sort -z --version-sort | while IFS= read -d '' -r file; do \
     mkdir -p "$newdir" && mv "$file" "$newdir" ;
     [[ ++sevenfile -eq 7 ]] && sevenfile=0 &&  ((newdir++));
done

答案3

如果你不介意所有内容被单独移动:

#! /bin/bash
for ((i = 1; ; i++))
do
    mkdir -p target-$i
    for j in $(seq $((i*7 - 6)) $((i*7)))
    do
        mv -t "target-$i" "source/image$j.tiff" || exit 1
    done
done

或者更简洁一点:

find source -type f -name 'image*.tiff' -print0 | \
  sort -z --version-sort | \
  xargs -0n7 bash -c 'TARGET=target-$((${1//[^0-9]/} / 7 + 1)); \
    echo mkdir -p "$TARGET"; \
    echo mv -t "$TARGET" "$@"' move-7

解释:

  1. -print0打印由 NUL ( \0) 字符分隔的文件名。这是将文件名作为输出传递给其他命令的最安全方法。
  2. sortwith-z查找以空字符分隔的输入,而 sort 版本允许我们安全地对可变长度的数字进行排序,因此它image2.tiff位于image119.tiff
  3. xargs可以使用 限制应用于每个命令的参数数量-n,因此我们在这里使用-n7-0用于以空字符分隔的输入。
  4. 我们提取第一个参数数字的商$((${1//[^0-9]/} / 7 + 1))-${1//[^0-9]/}删除参数中所有非数字的内容。整数除法确保我们得到商。
  5. 这应该更快,因为我们运行的正是所需的 s 数量mv

检查生成的命令,如果看起来没问题,则删除echos 后再次运行它。


JJoao 的回答带来rename首先,创建所有目录:

FILES=(source/image*.tiff)
COUNT=${#FILES[@]}
DIR_NUM=$((COUNT / 7 + 1))
seq 1 $DIR_NUM | xargs bash -c 'mkdir -p "${@/#/target-}"'

rename -n 's;source/image(\d+)\.tiff$;"target-".int($1 / 7 - 1)."/image".$1.".tiff";e' source/image*.tiff

事实上,我们可以将前四行应用到这里所有的解决方案,并跳过重复的mkdir -p

答案4

您可以使用 xargs(-n 或 --max-args)来设置要移动的文件数,但请记住参数限制为 ARG_MAX。

#!/bin/bash

images="./source/image*.tiff"
target="./target"

ls -v $images | xargs -n 7 | while read -a files; do mkdir $target/$((++n)) && mv -t $target/$n ${files[@]}; done

相关内容