"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 당 한 줄 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 루프 내부에 변수를 설정하려면 둘 사이의 차이점이 중요합니다. 다음을 참조하세요.내 변수가 하나의 "읽는 동안" 루프에서는 로컬이지만 겉보기에 유사한 다른 루프에서는 로컬이 아닌 이유는 무엇입니까?

관련 정보