我正在制作缩时视频,方法是将视频分割成单个图像,通过命令行使用 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、3 等),最终得到数百个目录,每个目录包含 7 个图像。
需要澄清的是,目录 1 应该包含图像 1-7,目录 2 应该包含图像 8-14,等等。
非常感谢您的帮助,我几乎被这个困住了。
答案1
下面的(python)脚本创建子文件夹并将文件组织到文件夹中:
此外:
- 该脚本计算文件夹的数量,并在文件夹名称中添加前导零,以便进行正确的排序(因为您提到了数千个文件,这意味着数百个文件夹)
- 每个文件夹的文件数量可能会有所不同,具体取决于您在脚本头部的设置
该脚本假设:
- 所有文件都有扩展名,所有文件都有相同扩大
- 您的文件名为
image1.tiff
,image2.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 $newdir
newdir
根据变量创建目录。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
解释:
-print0
打印由 NUL (\0
) 字符分隔的文件名。这是将文件名作为输出传递给其他命令的最安全方法。sort
with-z
查找以空字符分隔的输入,而 sort 版本允许我们安全地对可变长度的数字进行排序,因此它image2.tiff
位于image119.tiff
xargs
可以使用 限制应用于每个命令的参数数量-n
,因此我们在这里使用-n7
。-0
用于以空字符分隔的输入。- 我们提取第一个参数数字的商
$((${1//[^0-9]/} / 7 + 1))
-${1//[^0-9]/}
删除参数中所有非数字的内容。整数除法确保我们得到商。 - 这应该更快,因为我们运行的正是所需的 s 数量
mv
。
检查生成的命令,如果看起来没问题,则删除echo
s 后再次运行它。
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