このスクリプトで「ls」の出力を確実にキャプチャするにはどうすればよいですか?

このスクリプトで「ls」の出力を確実にキャプチャするにはどうすればよいですか?

次のスクリプトは、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

このスクリプトに関する私の質問は次のとおりです。

  1. if現在、ディレクトリに多くの映画がある場合でも、スクリプトは問い合わせの最初の四半期を実行します。それから私は理解しましたNo such file or directory
  2. 上映する映画がひとつだけなら私は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]シェルによって拡張され、代わりにlsfor-Rはディレクトリの内容を再帰的に一覧表示lsしますR。これを行うには、ファイルではなくディレクトリへのパスを渡す必要がありますが、それでもファイルのリストを表示します(非表示のファイル)、そのディレクトリコンポーネントはこれらのディレクトリにないため、見つかりませffmpegん。

--zeroさらに、最新バージョンのGNUオプションの実装を使用しないと、ls出力をls確実に後処理することはできません。

現在の作業ディレクトリとその下のどこにでもその拡張子リストを持つファイルを見つけるには、を使用できますfind。ファイルリスト(またはその項目)を保存するには、文字列/スカラー変数の代わりに配列変数を使用できます。

zshzshには(通常は動作する)再帰的な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スケープシーケンスを拡張するには、-Eforechoまたは-rfor を使用しますprint。追加の改行を印刷するには、echoliteralまたはwithの最後のパラメータに追加します$'\n'。さらに、オプションは設定されているかどうかにかかわらず許可されますbash(一部のシステムおよび/または一部の環境ではデフォルトで設定されています)。一般的に避けるのが最善ですが、空白で連結された引数を簡単に印刷できるので、ここではまだ使用します(使いやすく、bashはロード可能なプラグインとしてのみ存在し、システムにはデフォルトでbashに含まれています)。シェルがあることがわかっているので、この機能を使用して一度に複数のビデオを再生できます。echoposixxpg_echoechoprintfprintbashplay
  • プロンプトとユーザーメッセージは通常stderr(fd 2)に送信する必要があります。selectたとえば、これがの出力が行くところです。
  • 1行を読む構文は次のとおりです。IFS= read -r line、いいえread line。ただし、とにかくファイルパスは1行で構成する必要はありません。改行文字はファイル名のすべての文字と同じくらい有効なためです。
  • あなた*.[mM][kKpP][vV4]も一致しますfiles.mv4m4v)。

関連情報