bashスクリプトの最後のステップを助ける人がいますか?私がここまで来るのを手伝ってくれました。
#!/bin/bash
find . -type f \
-name '*.mp4' -o -name '*.mkv' \
-o -name '*.avi' -o -name '*.mov' |
while read -r file
do
size=$(stat -c %s "$file")
duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file")
codec=$(ffprobe -v error -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$file")
ratio=$(bc <<< "scale=2; $size / $duration")
echo "$file: codec=$codec, size=$size, duration=$duration, ratio=$ratio" | tee -a /home/user/Downloads/logfile
printf $ratio | awk '{print $1/1000}'| tee -a /home/user/Downloads/logfile
done
これで、すべての結果がテキストファイルに入ります。しかし、比率が次より大きいファイルのみを選択する方法はありますか?
@markp-fusoの要求に応じていくつかのことを明確にしました。
$ratioの例をいくつか使用して質問を更新してください。
$ratioの数字は、ビデオファイルのサイズ(バイト単位)をビデオファイルの持続時間(秒単位)で割ることによって生成されます。数字は約50kから1000kの間です。だから私はawk '{print $1/1000}'を使って50 - 1000の範囲にインポートしました。
そして、カットオフ/しきい値として何を使用しようとしますか? a) $ratio の値、b) awk で生成された値、または c) numfmt 呼び出しの結果に基づいてフィルタリングしますか?
良い点は、numfmt呼び出しを使用してバイトをメガバイトに増やしたいということです。ところで、それが切られました。したがって、削除できます。目的の結果が出るまで機能します。
./file1.mp4: codec=h264
aac, size=54886926, duration=94.900000, ratio=578365.92
578.366
./file2.mp4: codec=vp9
aac, size=15147100, duration=108.159000, ratio=140044.74
140.045
./file3.mp4: codec=vp9
aac, size=22306731, duration=109.947000, ratio=202886.21
202.886
長さが長いので、エンコード/縮小できるビデオ/オーディオファイルを見つけるためにこれを使用します。したがって、高い $ratio をエンコードできます。この値はスクリプトで簡単に調整できますが、約200〜400です。コーデックの効率によって異なります(使用されているコーデックを表示するために行を追加しました)。
だから、最終的に要件を満たすファイルだけを含むテキストファイルを持っていると思います。この場合、設定された比率よりも大きい。私は経験に基づいて決定を下します。
メモ:可能であれば、読み取れず(破損などのため)値のないファイルをテキストファイルに追加すると良いと思います。
比率を200に設定したと仮定すると、上記の3つの例に基づいて、txtファイルには次のものが含まれます。
./file1.mp4: codec=h264
aac, size=54886926, duration=94.900000, ratio=578365.92
578.366
./file3.mp4: codec=vp9
aac, size=22306731, duration=109.947000, ratio=202886.21
202.886
どんな助けでも大変感謝します。
乾杯
答え1
おそらく上部の近くでカットオフを宣言します。
# We only care about files with ratios GREATER than this:
cutoff=200000
その後、ループの下部付近で and コマンドをテストおよびステートメントにwhile
ラップします。echo
printf
if
...
ratio=$(bc <<< "scale=2; $size / $duration")
rc=$(bc <<< "$ratio > $cutoff")
if [[ "$rc" == "1" ]]
then {
echo "$file: codec=$codec, size=$size, duration=$duration, ratio=$ratio"
awk '{print $1/1000}' <<< "$ratio"
} | tee -a /home/user/Downloads/logfile
fi
done
答え2
要求された問題を解決する前に、まずスクリプトのさまざまな問題を解決する必要があります。まず、find
コマンドが間違っています。次に、改行文字を含むファイル名の場合、コマンドは失敗します。
お客様のfind
エラーはオプションをグループ化していないためです。これは、あなたのコマンドが名前がegで終わるディレクトリも見つけることを意味します.mov
。次のディレクトリを検討してください。
$ ls -lF
total 4
-rw-r--r-- 1 terdon terdon 0 Mar 18 18:37 'a bad'$'\n''file name.mp4'
drwxr-xr-x 2 terdon terdon 4096 Mar 18 18:38 foo.mov/
これには、ファイル(名前にスペースと改行文字が含まれています)とディレクトリが含まれていますfoo.mov
。ファイルを処理したいだけですが、ディレクトリfind
も返します。
$ find . -type f -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' -o -name '*.mov'
./foo.mov
./a bad?file name.mp4
すべての条件に適用するには、-type f
次のようにグループ化する必要があります。回答前の質問に関して:
$ find . -type f \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' -o -name '*.mov' \)
./a bad?file name.mp4
上記のように、括弧でグループ化すると(シェルで保護するにはエスケープするか引用符で囲む必要があります\(
)、コマンドは必要に応じてファイルのみを見つけることができます。'('
次の問題は改行です。find
印刷結果を\0
改行文字の代わりにNULL()バイトで区切ることで、この問題を解決できます。 GNU find
(Linuxシステムのデフォルト)を使用してこれを行うことができ、-print0
他の検索実装にはを使用できます-printf
。
これらの名前を処理しないと、次のエラーが発生します。
$ find . -type f \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' -o -name '*.mov' \) | while read -r file; do ls -l "$file"; done
ls: cannot access './a bad': No such file or directory
ls: cannot access 'file name.mp4': No such file or directory
正しい方法は次のとおりです。
$ find . -type f \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' -o -name '*.mov' \) -print0 | while read -r -d '' file; do ls -l "$file"; done
-rw-r--r-- 1 terdon terdon 0 Mar 18 18:37 './a bad'$'\n''file name.mp4'
ここでは必須ではありませんが、お勧めしIFS=
ます。バラよりこの回答たとえば、実際の操作は、入力区切り文字としてNULLを使用するようにオプションに指示することによって-d ''
実行されます。read
read
最後に、返される複数のコーデックを処理できる必要があります。これは、少なくとも私がテストしたファイルに対しては非常に一般的なものだからです。たとえば、
$ ffprobe -v error -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 foo.mkv
hevc
ac3
ass
ffprobe
したがって、tr '\n' ','
コマンドの出力などを介して改行を削除してください。
$ ffprobe -v error -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 foo.mkv | tr '\n' ','
hevc,ac3,ass,$
(最後は$
私のプロンプトで、ここに末尾の改行文字がないことを示します。)
要約すると、すでに変数に比率があるので、必要なのは、if
その比率がしきい値を超えているかどうかを簡単に確認することです。なぜ2つの比率($ratio
sum)があるのかわかりません$ratio / 1000
。私が見るには、実際にテストした比率を使用する方が合理的に見えますが、それはあなたの決定です。ジョブスクリプトは次のとおりです。
#!/bin/bash
threshold=$1
if [ -z "$threshold" ]; then
echo "No threshold given, using the default value of 200" >&2
threshold=200
fi
logfile="/home/user/Downloads/logfile"
find . -type f \
\( -name '*.mp4' -o -name '*.mkv' -o \
-name '*.avi' -o -name '*.mov' \) -print0 |
while IFS= read -r -d '' file
do
size=$(stat -c %s "$file")
duration=$(ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 "$file")
codec=$(ffprobe -v error -show_entries stream=codec_name \
-of default=noprint_wrappers=1:nokey=1 "$file" |
tr '\n' ',')
ratio=$(bc <<< "scale=2; $size / $duration")
# Check that a ratio was found, otherwise print an error
if [[ -z "$ratio" ]]; then
echo "No ratio found for '$file'" >&2
else
## Not sure why you want two separate values for ratio but...
ratio2=$(bc <<< "$ratio / 1000")
if [[ $ratio2 -ge $threshold ]]; then
printf '%s: codec=%s size=%s, duration=%s, ratio=%s\n' \
"$file" "$codec" "$size" "$duration" "$ratio" | tee -a "$logfile"
echo "$ratio2" | tee -a "$logfile"
fi
fi
done
これで、しきい値をパラメータとして(またはデフォルト値200なしで)実行できるようになりました。
script.sh 300
スクリプトに少しマイナーで、ほとんど外観的な変更を加え、いくつかの基本的なエラー処理を追加しましたが、まったく同じことを行う必要があります。出力は次のとおりです。
$ foo.sh 200
./file3.mkv: codec=h264,aac, size=764948534, duration=3488.131000, ratio=219300.40
219
./file7.mkv: codec=h264,aac, size=739550128, duration=3542.852000, ratio=208744.29
208
./file5.mkv: codec=h264,aac, size=688337512, duration=3439.637000, ratio=200119.23
200
./file1.mkv: codec=h264,aac, size=883534591, duration=3701.386000, ratio=238703.71
238
./file4.mkv: codec=h264,aac, size=828112726, duration=3769.898000, ratio=219664.49
219