我正在尝试创建一个脚本,该脚本应该读取视频文件夹并创建要处理的视频文件列表,以ffprobe
识别编解码器。未使用特定编解码器(在本例中为 HEVC)处理的视频应放入新列表中,以便由 进一步处理ffmpeg
。
ffprobe_input
我创建了一个非常基本的脚本,但在需要更改变量才能作为 的下一个输入传递的地方遇到了困难ffprobe
。
另外,即使脚本的这部分工作正常,我对如何在处理后创建过滤后的文件列表感到困惑ffprobe
,因为唯一的输出是一个单词,例如:hevc
或x264
。
下面是实际的脚本,以及我的笔记,这些笔记应该更具描述性,笔记中还有我尝试让事情发挥作用的一些方法。
这是该脚本的预期用途:./script.sh -p /path\ to\ videos
#!/bin/bash
#Read path (-p) input and exit on error.
while getopts p: flag
do
case "${flag}" in
p) vpath=${OPTARG};;
*) echo "usage: $0 [-p]" >&2
exit 1 ;;
esac
done
#Now we echo the path for neatness
echo -e "Selected root video path: $vpath";
#Check if the path is valid. The path must be escaped. Cd into the folder and execute: printf "%q\n" "$(pwd)"
[ -d "$vpath" ] && echo "Directory $vpath exists." || echo "Error: Directory $vpath does not exist. Tip: make sure the spaces are escaped in folder names, ex: ===video\ folder===."
#Prepare a list of video files with full escaped paths,ready for ffprobe/ffmpeg input.
find "$vpath" -type f \( -iname "*.mkv" -o -iname "*.mp4" -o -iname "*.avi" \) | sed 's/ /\\ /g' >> full_list.txt
#read the total number of lines from full_list.txt
nrl_total="$(wc -l full_list.txt | grep -Eo "[0-9]{0,7}")"
echo -e "There are a total of $nrl_total videos for further processing."
#read line number and pass to $ffprobe_input
# nrl=($(seq 1 "$nrl_total"))
# nrl={1..$nrl_total..1}
# for $nlr in {1..$nrl_total..1}; do
# nrl=({1..$nrl_total..1})
filename='full_list.txt'
nrl=1
while read line; do
echo "$nrl"
nrl=$((n+1))
#done < $filename
#ffprobe_input="$(sed -n 1p full_list.txt)" Use line number in "p" attribute, ex: 1p.
# ffprobe_input="$(sed -n 1p full_list.txt)"
ffprobe_input="$(sed -n "$nrl"p full_list.txt)"
#Now pass the input to ffprobe to determine if the videos are HEVC or not. Output is single word, ex: hevc or x264.
eval ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 -i "$ffprobe_input"
done < $filename
rm full_list.txt
答案1
假设您的文件名不包含换行符,您不需要以任何方式破坏它们。每个文件名的输出file
只有一行,因此只需存储它并循环生成的文件:
> non-hevc.txt # clear the output list
find "$vpath" -type f \( -iname "*.mkv" -o -iname "*.mp4" -o -iname "*.avi" \) \
> full_list.txt
while IFS= read -r file; do
result=$(ffprobe -v error -select_streams v:0 -show_entries \
stream=codec_name -of default=noprint_wrappers=1:nokey=1 -i "$file")
if [ "$result" != hevc ]; then
echo "$file" >> non-hevc.txt
fi
done < full_list.txt
rm -f full_list.txt
ffprobe
在这里,使用命令替换捕获的输出$(...)
并将其存储到result
,然后我们查看。
我看不出有任何理由sed -n "$nrl"p
在循环内读取文件名列表,因为read
已经读取了同一行。不过,我们确实需要IFS=
并且-r
不要破坏输入。
也没有理由用反斜杠转义任何空格,引的扩展"$file"
将变量的内容按原样传递给命令。撤消转义也很困难,当您使用 时eval
,它也会处理很多其他内容,并且会因括号等而呕吐。
不确定您是否要将输出附加find
到full_list.txt
已包含的内容,或重新创建列表。由于我们会立即处理列表,因此我认为忽略任何旧内容更有意义。
请注意,与 terdon 注释一样,您并不严格需要中间文件来存储文件名列表。您可以只执行find ... | while IFS= read file, do ...
, 或在 Bash/ksh/zsh 中进行进程替换while IFS= read file, do ... done < <(find ...)
。如果您想在 while 循环内设置变量,则两者之间的区别很重要,请参阅:为什么我的变量在一个“while read”循环中是本地变量,但在另一个看似相似的循环中却不是?