다음 스크립트는 현재 작업 디렉터리의 모든 미디어 파일을 자르도록 설계되었습니다.
#!/usr/bin/bash
trimmer() {
of=$(echo "${if}"|sed -E "s/(\.)([avimp4kvweb]{3,3}$)/\1trimmed\.\2/")
ffmpeg -hide_banner -loglevel warning -ss "${b}" -to "${ddecreased}" -i "${if}" -c copy "${of}"
echo "Success. Exiting .."
}
get_ddecreased() {
duration="$(ffprobe -v quiet -show_entries format=duration -hide_banner "${if}"|grep duration|sed -E s/duration=\([0-9]*\)\..*$/\\1/)"
echo ${duration}
ddecreased="$(echo "${duration} - ${trimming}"|bc -l)"
echo ${ddecreased}
}
rm_source() {
echo -e "Remove ${if}?[Y/n]?"
read ch
if [[ "${ch}" == 'y' ]]; then
rm "${if}"
fi
}
echo "How much of the beginning would you like to trim?"
read b
echo "How much of the end would you like to trim?"
read trimming
ls *.avi *.mkv *.mp4 *.vob >list_of_files
echo "Prompt before removing the source[Y/n]?"
read ch
while IFS="" read -r if || [[ -n "${if}" ]]; do
if [[ "${ch}" == 'y' ]]; then
get_ddecreased && trimmer && rm_source
elif [[ "${ch}" == 'n' ]]; then
get_ddecreased && trimmer && rm "${if}"
fi
echo $if
done <list_of_files
echo -e "Removing list_of_files."
rm list_of_files
첫 번째 파일 은 사용자에게 y
요청 시 트리밍을 선택 Prompt before removing the source[Y/n]
하고 완료하는지 묻는 메시지를 표시하도록 설계되었습니다 trimmer
.rm_source
그들의 입력을 기다립니다소스 파일을 삭제하기 전에 이는 스크립트가 입력을 기다리지 않고 echo -e "Removing list_of_files."
마치 while 루프가 전혀 없는 것처럼 즉시 계속되기 때문에 작동하지 않습니다. 사용자가 n
요청했을 때 선택할 때 while 루프도 실행되지 않습니다 Prompt before removing the source[Y/n]
. 스크립트가 echo -e "Removing list_of_files."
반복하는 대신 직접 계속됩니다 list_of_files
. 이유는 무엇입니까? 그러나 이 모든 줄을 주석 처리하면
if [[ "${ch}" == 'y' ]]; then
get_ddecreased && trimmer && rm_source
elif [[ "${ch}" == 'n' ]]; then
get_ddecreased && trimmer && rm "${if}"
fi
while 루프 내에서는 모든 줄이 list_of_files
화면에 인쇄됩니다.
내 코드에 문제가 있나요?
답변1
코드는 기본적으로 다음을 수행합니다.
foo () {
read variable
}
while read something; do
foo
done <input-file
목적은 터미널에서 무언가를 read
읽는 foo
것이지만 일부 파일에서 리디렉션되는 표준 입력 스트림의 컨텍스트에서 호출됩니다.
read
이는 in foo
이 터미널이 아닌 입력 파일의 입력 스트림에서 읽는다는 것을 의미합니다 .
표준 입력이 아닌 다른 파일 설명자에서 루프를 읽도록 하면 이 문제를 피할 수 있습니다.
foo () {
read variable
}
while read something <&3; do
foo
done 3<input-file
여기서 read
루프는 키워드 다음에 입력 파일에 연결된 파일 설명자 3에서 읽습니다 done
. 이를 통해 함수 read
내의 함수가 foo
원시 표준 입력 스트림을 자유롭게 사용할 수 있습니다.
bash
셸 에서는 추가 파일 설명자에 대해 하드 코딩된 값을 사용하는 대신 셸 변수에 설명자를 할당하도록 할 수 있습니다.
foo () {
read variable
}
while read something <&"$fd"; do
foo
done {fd}<input-file
$fd
10 이상의 정수로 설정할 수 있습니다 . 정확한 값은 중요하지 않습니다.
문제의 현재 코드에서는 파일 목록을 생성하고 읽는 것을 피하고 대신 파일 glob을 직접 사용하여 문제를 해결할 수도 있습니다.
for filename in *.avi *.mkv *.mp4 *.vob; do
if [ ! -e "$filename" ]; then
# skip non-existing names
continue
fi
# use "$filename" here
# ... and call your rm_source function
done
이렇게 하면 리디렉션이 완전히 방지됩니다. 이를 통해 코드에서 이름에 개행 문자가 포함된 이상한 파일을 처리할 수도 있습니다.
지정된 파일이 존재하는지 여부를 테스트하는 루프의 명령문은 if
패턴과 일치하는 이름이 없는 경우 기본적으로 쉘이 와일드카드 패턴을 유지하기 때문에 필요합니다. 다음을 설정하여 셸 if
에서 명령문을 제거할 수 있습니다.bash
nullglob
쉘 옵션 사용 shopt -s nullglob
. 이 옵션을 설정하면 bash
셸이 일치하지 않는 글로브를 완전히 제거합니다.
또한 와일드카드 패턴과 일치하는 이름이목차. 예를 들어 디렉토리가 있으면 나열됩니다 mydir.mp3
.ls
콘텐츠이 디렉토리의. 또한, 패턴과 일치하는 파일 이름이 대시로 시작하는 경우 사용된 코드가 ls
옵션 세트의 이름을 착각할 수 있습니다.