次のスクリプトは、play_movie.sh
自動的に映画(現在のディレクトリに映画が1つしかない場合)を選択して使用するように設計されています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
「現在のディレクトリに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
たとえば、これがの出力が行くところです。 - 1行を読む構文は次のとおりです。
IFS= read -r line
、いいえread line
。ただし、とにかくファイルパスは1行で構成する必要はありません。改行文字はファイル名のすべての文字と同じくらい有効なためです。 - あなた
*.[mM][kKpP][vV4]
も一致しますfiles.mv4
。m4v
)。