다음 스크립트는 play_movie.sh
자동으로 영화(현재 디렉터리에 영화가 하나만 있는 경우)를 선택하고 사용하도록 설계되었습니다 ffplay
. 그렇지 않으면 사용자에게 일련의 영화를 표시하고 사용자의 입력(재생할 영화)을 받아들이도록 설계되었습니다.
#!/usr/bin/bash
output_a=$(ls -R *.[aA][vV][iI] 2>/dev/null)
output_m=$(ls -R *.[mM][kKpP][vV4]] 2>/dev/null)
output_v=$(ls -R *.[vV][oO][bB]] 2>/dev/null)
all_exts="${output_a}${output_m}${output_v}"
ln_cnt=$(echo "${all_exts}" | wc -l)
if [[ "$ln_cnt" -eq 1 ]]; then
echo -e "Playing: ${all_exts}\n"
ffplay -hide_banner -infbuf -fs -sn -ast a:0 "${all_exts}"
elif [[ "$ln_cnt" -gt 1 ]]; then
printf "Select a file out of the list below"
ls -R *.[aA][vV][iI] 2>/dev/null
ls -R *.[mM][kKpP][vV4] 2>/dev/null
ls -R *.[vV][oO][bB] 2>/dev/null
read line; ffplay -hide_banner -infbuf -fs -sn -ast a:0 "$line"
fi
이 스크립트에 대한 내 질문은 다음과 같습니다.
if
현재 디렉터리에 많은 영화가 있더라도 스크립트는 문의 첫 번째 분기를 실행합니다. 그러면 나는 이해했다No such file or directory
.- 상영할 영화가 단 한 편뿐이라면 나는
No such file or directory
…
ls
과거의 결과 에 의존하는 데 어려움을 겪습니다 . 이 스크립트를 사용하지 않고 수정할 수 있습니까 find
?
답변1
"현재 디렉터리에 하나만 있는 경우" 부분이 정확하다고 가정합니다(즉현재 디렉터리에 있는 파일에만 관심이 있습니다. ls
다음은 물론 을 사용하지 않아도 됩니다 find
.
#!/usr/bin/bash -
shopt -s nullglob
set -- *.[aA][vV][iI] *.[mM][kKpP][vV4] *.[vV][oO][bB]
if [[ "$#" -eq 1 ]]; then
printf>&2 "Playing: %s\n\n" "$@"
ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$@"
elif [[ "$#" -gt 1 ]]; then
printf>&2 "Select a file out of the list below:\n"
printf>&2 "%s\n" "$@"
IFS= read -r line &&
ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$line"
fi
이 설정은 nullglob
일치하지 않는 glob을 제거한 다음 매개변수를 일치하는 모든 파일로 설정합니다.
그림에서 알 수 있듯이Stefan Chazeras의 답변select
, 사용자 경험을 개선하는 데 사용할 수 있습니다 ( select
위치 매개변수는 기본적으로 사용되며 위의 사용법과 잘 맞습니다 set
).
#!/usr/bin/bash -
shopt -s nullglob
set -- *.[aA][vV][iI] *.[mM][kKpP][vV4] *.[vV][oO][bB]
if [[ "$#" -eq 1 ]]; then
printf>&2 "Playing: %s\n\n" "$@"
ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$@"
elif [[ "$#" -gt 1 ]]; then
select video; do
ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$video"
exit
done
fi
답변2
이 방법으로는 사용할 수 없습니다 ls
. 이것들은 *.[aA][vV][iI]
쉘에 의해 확장되며 대신에 ls
for -R
는 디렉터리의 내용을 재귀적으로 나열 ls
하게 합니다 R
. 그렇게 하려면 파일이 아닌 디렉터리의 경로를 전달해야 하며 그런 다음에도 파일 목록을 출력합니다( 숨겨지지 않은 파일)에는 해당 디렉터리 구성 요소가 이러한 디렉터리에 없으므로 ffmpeg
찾을 수 없습니다.
--zero
또한 최신 버전의 GNU 옵션 구현을 사용하지 않으면 ls
출력을 ls
전혀 안정적으로 후처리할 수 없습니다.
현재 작업 디렉토리와 그 아래 어디에서나 해당 확장자 목록을 가진 파일을 찾으려면 를 사용할 수 있습니다 find
. 파일 목록(또는 해당 항목)을 저장하려면 문자열/스칼라 변수 대신 배열 변수를 사용할 수 있습니다.
zsh
zsh에는 (일반적으로 작동하는) 재귀 globbing 및 glob 한정자가 있으므로 여기서 대신 사용하면 bash
더 쉬워집니다. 즉, 파일 목록을 해당 유형으로 제한할 수도 있습니다.정기적인. Glob은 기본적으로 숨겨진 파일도 건너뜁니다(비슷 ls
하지만 find
수동으로 건너뛸 필요는 없음).
#! /usr/bin/zsh -
set -o extendedglob
videos=( **/*.(#i)(avi|mkv|mp4|vob)(N-.) )
play() {
print -ru2 Playing $argv
ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- $argv
}
case $#videos in
(0) print -u2 No video found; exit 1;;
(1) play $videos;;
(*) print -u2 Select a video:
select video in $videos; do
play $video || exit
break
done;;
esac
bash
(GNU 쉘) + GNU를 사용하면 find
다음을 수행할 수 있습니다.
#! /usr/bin/bash -
readarray -td '' videos < <(
LC_ALL=C find . \
-regextype posix-extended \
-name '.?*' -prune -o \
-iregex '.*\.(avi|mkv|mp4|vob)' \
-xtype f \
-printf '%P\0' |
sort -z
)
shopt -u xpg_echo
play() {
echo>&2 -E Playing "$@"
ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$@"
}
case ${#videos[@]} in
(0) echo>&2 No video found; exit 1;;
(1) play "${videos[@]}";;
(*) echo>&2 Select a video:
select video in "${videos[@]}"; do
play "$video" || exit
break
done;;
esac
기타 참고사항:
echo -e
파일 이름에 문자가 포함되어 있으면 중단됩니다\
. 여기 있어요아니요e
스케이프 시퀀스를 확장 하려면-E
forecho
또는-r
for 를 사용하세요print
. 추가 줄바꿈을 인쇄하려면echo
literal 또는 with 의 마지막 매개변수 에 추가하세요$'\n'
. 또한 옵션은 설정 여부에 관계없이 허용됩니다bash
(일부 시스템 및/또는 일부 환경에서는 기본적으로 설정됨). 일반적으로 피하는 것이 가장 좋지만 공백으로 연결된 인수를 쉽게 인쇄할 수 있기 때문에 여기서는 여전히 사용합니다(사용하기가 더 번거롭고 bash는 로드 가능한 플러그인으로만 존재하며 시스템에는 기본적으로 bash에 포함되어 있습니다). 쉘이 있다는 것을 알고 있으므로 이 기능을 사용하여 한 번에 여러 비디오를 재생할 수 있습니다.echo
posix
xpg_echo
echo
printf
print
bash
play
- 프롬프트와 사용자 메시지는 일반적으로 stderr(fd 2)로 전송되어야 합니다.
select
예를 들어, 이것이 의 출력이 가는 곳입니다. - 한 줄을 읽는 구문은 다음과 같습니다.
IFS= read -r line
, 아니요read line
. 그러나 어쨌든 파일 경로는 한 줄로 구성될 필요가 없습니다. 개행 문자는 파일 이름의 모든 문자만큼 유효하기 때문입니다. - 당신
*.[mM][kKpP][vV4]
도 일치할 것files.mv4
입니다.m4v
).