我正在尝试编写一个脚本,用于获取当前工作目录子目录中的多个图像序列系列,并通过 ffmpeg 发送它们,以在以目录命名的当前工作目录中创建视频文件。由于图像序列名称各不相同,序列的起始编号也各不相同,因此这很复杂,但真正的问题是我对 bash 脚本还不熟悉。以下是文件的示例:
directoryFirstRender01
renderOne0032.png
renderOne0033.png
renderOne0034.png
directoryFourthRender01
renderFour4253.png
renderFour4254.png
renderFour4255.png
directoryFifthRender01
renderFiveTwo1367.png
renderFiveTwo1368.png
renderFiveTwo1369.png
以下是该脚本的粗略概述,其中有几个我知道的问题,可能还有很多我不知道的问题。我不知道它有多少问题的原因是,我在获取和解析文件名时遇到了困难,如果没有这些,我就无法测试其余部分:
#!/bin/bash
for DIR in (ls -d */); do
1STFILE=(ls $dir/ | sort -n | head -1)
STARTNO=${1STFILE:(-8):4}
IMGSEQ=${1STFILE%????.*}
EXTEN=${1STFILE*.}
ffmpeg -start_number $STARTNO -i $IMGSEQ%04d.$EXTEN $DIR.mkv
done
我目前知道的主要问题是:
- 我不知道如何获取目录中第一个文件的文件名。
ls dir/ | sort -n | head -1
在终端中有效,但在脚本中无效。 - 获取第一个文件的第一个数字的子字符串提取仅适用于 4 位数字的图像序列。有没有办法让它也接受
renderSix00001.png-renderSix99999.png
和renderSeven001.png-renderSeven999.png
?获取的行也有问题$IMGSEQ
,并且%04d
ffmpeg 行中的 需要以某种方式进行更改。 - 我认为我将在变量与不带括号的 ffmpeg 输入文件名
$IMGSEQ
混合时遇到麻烦,但我还没有走到那一步。我在那里使用什么语法?(像这样的东西就是为什么深入脚本编写很糟糕的原因)%04d
$IMGSEQ(%04d).$EXTEN
$IMGSEQ {%04d}.$EXTEN
- (小问题:1.我知道使用
ls
infor DIR in (ls -d */)
是不被认可的,但我不知道如何过滤掉当前工作目录中的任何文件并只对目录进行操作。)
我确信这个脚本看起来一团糟。任何让整个事情正常运转的总体指导都会非常受欢迎,但如果没有人有耐心指导我完成整个过程,如果我能得到一些帮助来获取和解析文件名,也许我可以自己修复其余部分。谢谢。
更新 1:(采纳 Ron 的建议后)
再次感谢 Ron!这是接近最终版本的脚本:
#!/bin/bash
for DIR in $(ls -d */)
do
FIRSTFILE=$(ls $DIR | sort -n | head -1)
STARTNO=$(echo $FIRSTFILE | grep -Eo "[0-9]+")
DIGITNO=${#STARTNO}
IMGSEQ=${FIRSTFILE%????.*}
EXTEN=${FIRSTFILE#*.}
OUTPUT=${DIR%/}
ffmpeg -start_number $STARTNO -i "$DIR$IMGSEQ"%0"$DIGITNO"d".$EXTEN" $OUTPUT.mkv
done
由于 Ron 的帮助,$STARTNO
变量现在可以接受多位数字长度,因此我在行中使用长度参数扩展$DIGITNO
来获取部分中使用的数字,以便%04d
根据需要进行扩展,这样也可以。我希望自由使用将与周围变量分开不会被视为不良形式(如果是,正确的方法是什么?)。脚本中唯一缺少的部分(我想!)是如何使其接受多位数字长度。我现在对此没有任何想法。如果有人知道,我将不胜感激,但也许我可以通过参数扩展文档找到它,好像我一生都没有受够那样的东西。:)%03d
%05d
"
%04d
$IMGSEQ
更新 2:(成功!)
搞定了!(如何让 IMGSEQ 接受涉及多个数字长度的名称)根据 Ron 的建议,$STARTNO
我(echo $FIRSTFILE | grep -Eo "[0-9]+")
得出了
IMGSEQ=$(echo ${FIRSTFILE%.*} | grep -iEo "[a-z]+")
${FIRSTFILE%.*}
获取第一个文件并删除扩展名。- grep 是模式搜索
- 该
-i
部分-iEo
是使 grep 接受大写和小写模式匹配。 -E
的部分是-iEo
(引用自man grep
)“将 PATTERN 解释为扩展的正则表达式。”不管那是什么意思。- 该
-o
部分-iEo
仅打印匹配的模式。 [a-z]
是匹配字母表中任意字母的模式+
告诉 grep 前一个字母模式应该匹配“一次或多次”(因此一遍又一遍地执行以获取所有字母)。
它的一个限制是它不能处理带有特殊字符(如-
或)的文件名_
,但我现在可以忍受。
这是半决赛剧本!
#!/bin/bash
for DIR in $(ls -d */)
do
FIRSTFILE=$(ls $DIR | sort -n | head -1)
STARTNO=$(echo $FIRSTFILE | grep -Eo "[0-9]+")
DIGITNO=${#STARTNO}
IMGSEQ=$(echo ${FIRSTFILE%.*} | grep -iEo "[a-z]+")
EXTEN=${FIRSTFILE#*.}
OUTPUT=${DIR%/}
ffmpeg -n -start_number $STARTNO -i "$DIR$IMGSEQ"%0"$DIGITNO"d".$EXTEN" $OUTPUT.mkv
done
因此,在一个目录中运行一些与上面的示例目录类似的目录(除了我添加了一个用超过 4 个零填充的图像序列以确保它也能正常工作),该脚本将一个接一个地运行以下 ffmpeg 行:
ffmpeg -n -start_number 0032 -i directoryFirstRender01/renderOne%04d.png directoryFirstRender01.mkv
ffmpeg -n -start_number 4253 -i directoryFourthRender01/renderFour%04d.png directoryFourthRender01.mkv
ffmpeg -n -start_number 01367 -i directoryFifthRender01/renderFiveTwo%05d.png directoryFifthRender01.mkv
太完美了!再次感谢你的帮助,Ron!如果没有你的帮助,我肯定无法完成。
答案1
我不知道如何获取目录中第一个文件的文件名。ls dir/ | sort -n | head -1 在终端中有效,但在脚本中无效。
您可能想要重写:
for DIR in (ls -d */); do
1STFILE=(ls $dir/ | sort -n | head -1)
作为
for DIR in (ls -d */)
do
1STFILE=$(ls $DIR | sort -n | head -1)
有没有办法让它
renderSix00001.png-renderSix99999.png
也接受renderSeven001.png-renderSeven999.png
?
如果你已遵循上述操作,则:
STARTNO=$(echo $1STFILE | grep -Eo "[0-9]+")
应该获取文件名中的所有数字。
我在那里使用什么语法
$IMGSEQ(%04d).$EXTEN
或者$IMGSEQ {%04d}.$EXTEN
可能使用什么语法?
把那个东西放进""
去:
ffmpeg -start_number $STARTNO -i "$IMGSEQ%4d.$EXTEN" "$DIR.mkv"
现在,如果你使用 just,"$IMGSEQ%4d.$EXTEN"
你就会遇到一个问题(试试看是什么问题!)。所以"$DIR$IMGSEQ%4d.$EXTEN"
如果你使用"$DIR.mkv"
它,将会创建一个隐藏文件.mkv
,这不是你想要的。我认为一个不太酷的方法是通过删除/
变量中的后缀来仅存储目录名称:
OUTPUT=$(echo $DIR | sed 's/\/$//')
ffmpeg
并在如下中使用:
ffmpeg -start_number $STARTNO -i "$DIR$IMGSEQ%4d.$EXTEN" "$OUTPUT.mkv"