「whileループ」を使用した後、bashスクリプトでデータを処理するのに問題があります。

「whileループ」を使用した後、bashスクリプトでデータを処理するのに問題があります。

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

ファイル名に改行文字が含まれていないと仮定すると、何らかの方法でファイル名を破損する必要はありません。出力はfilenameごとに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ループ内に変数を設定するには、2つの違いが重要です。以下を参照してください。私の変数が1つの「読み込み中」ループではローカルですが、一見似ている他のループではローカルではないのはなぜですか?

関連情報