以下脚本接受两个输入,sourceFile="${1}"
并且trimFile="${2}"
. 这$sourceFile
是一个视频文件,将根据$trimFile
. 这$trimFile
是一个具有以下结构的文本文件(与此问题相关的实际文件):
00:49:30,00:53:00 DescriptionA
03:33:30,03:38:40 DescriptionB
04:54:32,04:55:37 DescriptionC
在下面$trimFile
的脚本中使用逗号和空格作为分隔符。虽然相当明显,但每一行都代表一个要从$sourceFile
. 进一步地,第一个字段是要修剪的剪辑的开始时间,第二个字段是要修剪的剪辑的结束时间,最后一个字段是剪辑的描述。
我的问题不在于修剪$sourceFile
. 我正在尝试使用相对于原始视频文件日期的日期和时间重命名新剪辑。每个$sourceFile
和$trimFile
的命名类似于以下示例(这是我目前使用的实际文件名):2017-05-15_14-17-22 (2017-05-16 00-45-41.151674100 -0400) (HEVC27).mp4
和2017-05-15_14-17-22 (2017-05-16 00-45-41.151674100 -0400) (HEVC27).txt
,分别。同样,虽然相当明显,日期组件是Year: 2017
, Month: 05
, Day: 16
, Hour: 14
, Minute: 17
, 和Second:22
(忽略日期是括号,因为它是带有错误 UTC 调整日期的旧参考)。
在下面的脚本中,如何提取文件中的日期/时间以及如何提取文件中的日期/时间应该很明显$trimFile
。为了说明这个问题,我需要在注释掉和不注释掉某些行的情况下显示它。在这里,某些行被注释掉了(这将在我接下来讨论的时候有意义)。
01: sourceFile="${1}"
02: trimFile="${2}"
03:
04: IFS=$'\n'
05:
06: dos2unix "$trimFile"
07: numberOfSegments=`cat "$trimFile" | wc -l`
08: numberOfSegments=$((numberOfSegments + 1))
09: extension=`echo "$sourceFile" | awk -F'.' '{print $NF}'`
10:
11: base=`echo "$sourceFile" | sed -e "s|.$extension||g"`
12:
13: #~/bin/ffmpeg -i "${sourceFile}" -c:v copy "/dev/shm/$base.${extension}"
14: #sourceFile="/dev/shm/$base.${extension}"
15:
16: # File date/time information
17: origYear="${sourceFile:0:4}"
18: origMonth="${sourceFile:5:2}"
19: origDay="${sourceFile:8:2}"
20: origHour="${sourceFile:11:2}"
21: origMinute="${sourceFile:14:2}"
22: origSecond="${sourceFile:17:2}"
23:
24: origDate="${origYear}-${origMonth}-${origDay} ${origHour}:${origMinute}:${origSecond}"
25:
26: for (( i=1;i<="$numberOfSegments";i++ ))
27: do
28:
29: lineEntry=`cat "$trimFile" | head -"$i" | tail -1`
30:
31: startHour=`echo "$lineEntry" | awk -F'[:,]' '{print $1}'`
32: startMinute=`echo "$lineEntry" | awk -F'[:,]' '{print $2}'`
33: startSecond=`echo "$lineEntry" | awk -F'[:,]' '{print $3}'`
34:
35: endHour=`echo "$lineEntry" | awk -F'[:,]' '{print $4}'`
36: endMinute=`echo "$lineEntry" | awk -F'[:,]' '{print $5}'`
37: endSecond=`echo "$lineEntry" | awk -F'[:,]' '{print $6}'`
38:
39: description=`echo "$lineEntry" | awk -F'[:, ]' '{print $7}'`
40:
41: beginSeconds=`awk "BEGIN {print ($startHour*3600+$startMinute*60+$startSecond)}"`
42: stopSeconds=`awk "BEGIN {print ($endHour*3600+$endMinute*60+$endSecond)}"`
43: duration=`awk "BEGIN {print $stopSeconds-$beginSeconds}"`
44:
45: newDate=$(date -d "@$(( $(date -d "${origDate}" +%s) + ${beginSeconds}))" +'%Y-%m-%d_%H-%M-%S')
46:
47: new="${newDate}_${description}"
48: echo "${lineEntry}"
49: echo "${origDate}"
50: echo "${beginSeconds}"
51: echo "${new}"
52: echo ""
53:
54: #~/bin/ffmpeg -n -vsync drop -fflags +genpts -i "$sourceFile" -ss "$beginSeconds" -t "$duration" -c:v libx265 -crf 27 -preset slow "$new.mkv"
55:
56:
57: done
58:
59: #rm "/dev/shm/${base}.${extension}"
当我以这种形式执行脚本时,我得到以下与脚本中第 48-52 行相对应的输出:
01: 00:49:30,00:53:00 DescriptionA
02: 2017-05-15 14:17:22
03: 2970
04: 2017-05-15_15-06-52_DescriptionA
05:
06: 03:33:30,03:38:40 DescriptionB
07: 2017-05-15 14:17:22
08: 12810
09: 2017-05-15_17-50-52_DescriptionB
10:
11: 04:54:32,04:55:37 DescriptionC
12: 2017-05-15 14:17:22
13: 17672
14: 2017-05-15_19-11-54_DescriptionC
15:
16: 04:54:32,04:55:37 DescriptionC
17: 2017-05-15 14:17:22
18: 17672
19: 2017-05-15_19-11-54_DescriptionC
如您所见,预期的新日期/时间在第 4、9、14 行中正确输出(我不确定为什么最后一行$trimFile
输出两次,但目前这不是我关心的问题)。
问题在于当我从脚本中删除注释行(第 13、14、54、59 行)时文件的实际重命名,因此脚本现在看起来像这样:
01: sourceFile="${1}"
02: trimFile="${2}"
03:
04: IFS=$'\n'
05:
06: dos2unix "$trimFile"
07: numberOfSegments=`cat "$trimFile" | wc -l`
08: numberOfSegments=$((numberOfSegments + 1))
09: extension=`echo "$sourceFile" | awk -F'.' '{print $NF}'`
10:
11: base=`echo "$sourceFile" | sed -e "s|.$extension||g"`
12:
13: ~/bin/ffmpeg -i "${sourceFile}" -c:v copy "/dev/shm/$base.${extension}"
14: sourceFile="/dev/shm/$base.${extension}"
15:
16: # File date/time information
17: origYear="${sourceFile:0:4}"
18: origMonth="${sourceFile:5:2}"
19: origDay="${sourceFile:8:2}"
20: origHour="${sourceFile:11:2}"
21: origMinute="${sourceFile:14:2}"
22: origSecond="${sourceFile:17:2}"
23:
24: origDate="${origYear}-${origMonth}-${origDay} ${origHour}:${origMinute}:${origSecond}"
25:
26: for (( i=1;i<="$numberOfSegments";i++ ))
27: do
28:
29: lineEntry=`cat "$trimFile" | head -"$i" | tail -1`
30:
31: startHour=`echo "$lineEntry" | awk -F'[:,]' '{print $1}'`
32: startMinute=`echo "$lineEntry" | awk -F'[:,]' '{print $2}'`
33: startSecond=`echo "$lineEntry" | awk -F'[:,]' '{print $3}'`
34:
35: endHour=`echo "$lineEntry" | awk -F'[:,]' '{print $4}'`
36: endMinute=`echo "$lineEntry" | awk -F'[:,]' '{print $5}'`
37: endSecond=`echo "$lineEntry" | awk -F'[:,]' '{print $6}'`
38:
39: description=`echo "$lineEntry" | awk -F'[:, ]' '{print $7}'`
40:
41: beginSeconds=`awk "BEGIN {print ($startHour*3600+$startMinute*60+$startSecond)}"`
42: stopSeconds=`awk "BEGIN {print ($endHour*3600+$endMinute*60+$endSecond)}"`
43: duration=`awk "BEGIN {print $stopSeconds-$beginSeconds}"`
44:
45: newDate=$(date -d "@$(( $(date -d "${origDate}" +%s) + ${beginSeconds}))" +'%Y-%m-%d_%H-%M-%S')
46:
47: new="${newDate}_${description}"
48: echo "${lineEntry}"
49: echo "${origDate}"
50: echo "${beginSeconds}"
51: echo "${new}"
52: echo ""
53:
54: ~/bin/ffmpeg -n -vsync drop -fflags +genpts -i "$sourceFile" -ss "$beginSeconds" -t "$duration" -c:v libx265 -crf 27 -preset slow "$new.mkv"
55:
56:
57: done
58:
59: rm "/dev/shm/${base}.${extension}"
60:
61:
脚本创建的文件命名如下:
1969-12-31_19-49-30_DescriptionA.mkv
1969-12-31_22-33-30_DescriptionB.mkv
1969-12-31_23-54-32_DescriptionC.mkv
显然,用于命名文件的日期与我没有重新编码视频而只是测试新日期变量是否正确计算时创建的输出不同。
所以,我的问题归结为这个,为什么在做了一些日期/时间数学之后,日期/时间在回显到粗壮时是正确的,但在用于命名编码后的文件时却大错特错。
谢谢!
通过取消注释
您使后面的行提取了错误的片段。
例如,现在
$origYear
扩展为/dev
.我希望
date -d
抛出类似于date: invalid date '/dev-sh-/2 17:05:15'
. 也许您date -d
没有验证其输入(或者您是否忽略了错误?)。您可以通过在更改 的值之前将子字符串分配给等
origYear
来解决此特定问题。origMonth
sourceFile
如果将来有人引用这篇文章,下面是更正的工作脚本。除了在这篇文章中解决的问题之外,还有其他错误也得到了纠正(即 ffmpeg 命令以及命令的位置
-ss
和命令-t
中的位置。