使用“while 循环”并随后在 bash 脚本中处理数据的问题

使用“while 循环”并随后在 bash 脚本中处理数据的问题

我正在尝试创建一个脚本,该脚本应该读取视频文件夹并创建要处理的视频文件列表,以ffprobe识别编解码器。未使用特定编解码器(在本例中为 HEVC)处理的视频应放入新列表中,以便由 进一步处理ffmpeg

ffprobe_input我创建了一个非常基本的脚本,但在需要更改变量才能作为 的下一个输入传递的地方遇到了困难ffprobe

另外,即使脚本的这部分工作正常,我对如何在处理后创建过滤后的文件列表感到困惑ffprobe,因为唯一的输出是一个单词,例如:hevcx264

下面是实际的脚本,以及我的笔记,这些笔记应该更具描述性,笔记中还有我尝试让事情发挥作用的一些方法。

这是该脚本的预期用途:./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,它也会处理很多其他内容,并且会因括号等而呕吐。

不确定您是否要将输出附加findfull_list.txt已包含的内容,或重新创建列表。由于我们会立即处理列表,因此我认为忽略任何旧内容更有意义。

请注意,与 terdon 注释一样,您并不严格需要中间文件来存储文件名列表。您可以只执行find ... | while IFS= read file, do ..., 或在 Bash/ksh/zsh 中进行进程替换while IFS= read file, do ... done < <(find ...)。如果您想在 while 循环内设置变量,则两者之间的区别很重要,请参阅:为什么我的变量在一个“while read”循环中是本地变量,但在另一个看似相似的循环中却不是?

相关内容