我下载了一些视频,其中一些视频分为几个部分:
001 aaaa part1.mp4
001 aaaa part2.mp4
002 bbbb part1.mp4
003 cccc part1.mp4
003 cccc part2.mp4
004 dddd part1.mp4
004 dddd part2.mp4
005 eeee part1.mp4
006 ffff part1.mp4
007 gggg part1.mp4
008 hhhh part1.mp4
在上述文件中,001 ...
003 ...
和004 ...
是拆分文件,而其他文件则不是,即使名称中包含part1.mp4
。
我想找到并合并拆分文件和一些工具,例如mp4box
。
为了做到这一点,我需要做:
将文件按开头的每个文件的编号分组,以及包含多个文件的组,它是我需要的零件文件。因此,将找到001/003/004
文件。
删除part?.mp4
为其生成新文件名。对于001 aaaa part1.mp4
和001 aaaa part2.mp4
,它会生成001 aaaa.mp4
致电mp4box -add "001 aaaa part1.mp4" -cat "001 aaaa part2.mp4" "001 aaaa.mp4"
将其合并
对所有零件文件重复此操作
我尝试用fish / bash做这个,但失败了。最后,我使用其他一些编程语言来完成,但我仍然想知道是否有可能用fish或bash来做。
答案 0 :(得分:4)
在鱼类中,我不会遍历文件而是遍历数字,所以
for num in (printf '%03d\n' (seq 1 8)) # Pad the numbers to the given length - assuming they are all three digits long
set -l files $num* # This will generate a list with as many elements as there are matching files, so if there's no file, there's zero elements
count $files >/dev/null; or continue # Skip numbers that aren't used
set -l name (string replace -r 'part.' '' -- $files[1]) # Or sed if you are using fish < 2.3
if test (count $files) -gt 1
mp4box -add $files[1] -cat $files[2..-1] $name # Assuming all but the last argument after cat are taken to be files to concatenate, otherwise it's a little more complicated
else
mv $files $name # If there's one file, just rename it
end
end
答案 1 :(得分:2)
以下脚本可能对您有所帮助。我编写了您需要修改的一般模式,以便与mp4box
一起使用:
#!/bin/bash
# Iterate over all file name prefixes which represent a split file.
for i in 001 003 004; do
# An array to hold paths of split files.
arr=()
# Find all files in present-working-directory ( PWD ) which have the current prefix in their file name,
# and add them to the split files array sorted by 'part' number.
while read -rd '' f; do
# The index of the entry. Parts must be sorted.
num=${f##* part}
num=${num%.*}
# Put "$f" in the correct array cell, according to its part index.
arr[10#$num]=$f
done < <(find . -type f -name "$i *.mp4" -print0)
# We're making arr not sprase, so we'll know for sure that arr[0] is not empty,
# from which we'll derive the destination file name.
arr=("${arr[@]}")
# If we have more than a single split file in the split files array, then
if (( ${#arr[@]} > 1 )); then
# Create a new name for the destination mp4.
new_name="${arr[0]% *}.mp4"
# And...
printf '%s %s\n' "Use mp4box to combine the following files to a new file named" "$new_name"
printf '%s\n' "${arr[@]}"
fi
done
让我们测试一下(脚本的名称是 sof ):
$ ./sof
Use mp4box to combine the following files to a new file named ./001 aaaa.mp4
./001 aaaa part1.mp4
./001 aaaa part2.mp4
Use mp4box to combine the following files to a new file named ./003 cccc.mp4
./003 cccc part1.mp4
./003 cccc part2.mp4
Use mp4box to combine the following files to a new file named ./004 dddd.mp4
./004 dddd part1.mp4
./004 dddd part2.mp4
如果您确实想要实现的目标,mp4box
的正确参数可以像这样创建(当然在if (( ${#arr[@]} > 1 )); then
块内):
# Create arguments to mp4box's -add option (i.e. file1 -cat file2 -cat file3 ...)
mp4args=("${arr[0]}"); for entry in "${arr[@]:1}"; do mp4args+=(-cat "$entry"); done
# Execute mp4box for current split files:
mp4box -add "${mp4args[@]}" "$new_name"
# Empty mp4args array here, or at the begining of the `for` loop.
mp4args=()
让我们在echo
之前加上mp4box
,以确定我们要执行的内容,并对其进行测试:
$ ./sof
Use mp4box to combine the following files to a new file named ./001 aaaa.mp4
./001 aaaa part1.mp4
./001 aaaa part2.mp4
===
mp4box -add ./001 aaaa part1.mp4 -cat ./001 aaaa part2.mp4 ./001 aaaa.mp4
===
Use mp4box to combine the following files to a new file named ./003 cccc.mp4
./003 cccc part1.mp4
./003 cccc part2.mp4
===
mp4box -add ./003 cccc part1.mp4 -cat ./003 cccc part2.mp4 ./003 cccc.mp4
===
Use mp4box to combine the following files to a new file named ./004 dddd.mp4
./004 dddd part1.mp4
./004 dddd part2.mp4
===
mp4box -add ./004 dddd part1.mp4 -cat ./004 dddd part2.mp4 ./004 dddd.mp4
===
答案 2 :(得分:-1)
假设有合适的文件名(名称中没有附加的“。”,当前目录中没有奇怪的其他文件......):
for prefix in `ls | sed -e 's/ .*//' | uniq -d` ; do
first=`ls $prefix* | head -1`
name=`echo "$first" | sed -e 's/ part.+\\.//'
cmd="mp4box -add '$first'"
for rest in `ls $prefix* | tail +2` ; do
cmd="$cmd -cat $rest"
done
$cmd $name
done
未测试。适当地测试和定制。
编辑:将其视为bash伪代码,请参阅注释以了解其中的明显问题。