使用“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
假設您的文件名不包含換行符,則無需以任何方式破壞它們。每個文件名的輸出
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 註釋一樣,您並不嚴格需要中間文件來儲存文件名列表。你可以做 just
find ... | while IFS= read file, do ...
,或者在 Bash/ksh/zsh 中使用程序替換while IFS= read file, do ... done < <(find ...)
。如果您想在 while 循環中設置變數,兩者之間的區別很重要,請參閱:為什麼我的變數在一個“while read”循環中是局部的,但在另一個看似相似的循環中卻沒有?