順序付きリストをサブリストに分割

順序付きリストをサブリストに分割

max(x) = 9999prefix_0000.mp3というファイルのリストがあります。prefix_x.mp3

Bashスクリプトがあります。

...
sox prefix_*.mp3 script_name_output.mp3 # this fails because maximum number is 348
rm prefix_*.mp3
...

ソートされたmp3ファイルのリストをサブリスト(順番に保持)に分割し、徐々に削除し、soxbashスクリプトから不要なファイルを削除する最善の方法は何ですか?

ベストアンサー1

まず、リストを Bash 配列として収集します。ファイルが現在のディレクトリにある場合は、次のものを使用できます。

files=(prefix_????.mp3)

または、検索と並べ替えを使用できます。

IFS=$'\n' ;
files=($(find . -name 'prefix_*.mp3' printf '%p\n' | sort -d))

この設定はIFSBash に改行文字でのみ分割するよう指示します。ファイル名とディレクトリ名にスペースが含まれていない場合は省略できます。

または、ファイルからファイル名を読み取ることができます(たとえば、filelist1行に1つの名前、空白行なし)。

IFS=$'\n'
files=($(<filelist))

空白行がある場合は、以下を使用してください。

IFS=$'\n'
files=($(sed -e '/$/ d' filelist))

次に、各スライスに必要なファイル数、一時アキュムレータファイル名、最終結合ファイル名を決定します。

s=100
src="combined-in.mp3"
out="combined-out.mp3"

その後、リストを分割して各サブリストを処理します。

while (( ${#files[@]} > 0 )); do
    n=${#files[@]}

    # Slice files array into sub and left.
    if (( n <= s )); then
        sub=("${files[@]}")
        left=()
    else
        (( n-= s ))
        sub=("${files[@]:0:s}")
        left=("${files[@]:s:n}")
    fi

    # If there is no source file, but there is
    # a sum file, rename sum to source.
    if [ ! -e "$src" -a -e "$out" ]; then
        mv -f "$out" "$src"
    fi

    # If there is a source file, include it first.
    if [ -e "$src" ]; then
        sub=("$src" "${sub[@]}")
    fi

    # Run command.
    if ! sox "${sub[@]}" "$out" ; then
        rm -f "$out"
        echo "Failed!"
        break
    fi

    rm -f "$src"
    echo "Done up to ${sub[-1]}."
    files=("${left[@]}")

    # rm -f "${sub[@]}"
done

報告が失敗すると、soxループは早期に終了します。それ以外の場合は、処理されたバッチの姓を出力します。

iffor コマンドを使用してsoxエラーを検出し、エラーが発生した場合は出力ファイルを削除します。また、コマンドが成功するまで配列の変更を延期filesするので、sox個々のファイルを安全に編集/修正してからループを再実行して、中断したwhile部分から続行できます。

ディスク容量が不足している場合は、最後から2行目のコメントを外して、正常にマージされたすべてのrm -f "${sub[@]}"ファイルを削除できます。


上記は、最初の部分を取り上げ続けています。

ffmpeg以下の説明で説明するように、sox最初にファイルをリンクしてから(再エンコードを使用せずに)再エンコードを使用すると、結果がはるかに良くなりますsox。 (またはもちろん、最初に録音することもできます。)

まず、パイプで区切られたファイル名(文字列)のリストを作成し、

files="$(ls -1 prefix_????.mp3 | tr '\n' '|')"

最後の余分なチューブを取り外し、

files="${files%|}"

記録せずに供給しますffmpeg

ffmpeg -i "concat:$files" -codec copy output.mp3

実行したいかもしれません

ulimit -n hard

開いているファイルの数を現在のプロセスで許可される最大値に増やします(ハード制限);を使用してクエリを実行できますulimit -n。 (ffmpeg concat:ソースを順次オープンするか、一度にオープンするかはよく覚えていません。)

これを何度も実行する場合は、すべてを簡単なスクリプトに入れます。

#!/bin/bash
export LANG=C LC_ALL=C
if [ $# -le 2 -o "$1" = "-h" -o "$1" = "--help" ]; then
    exec >&2
    printf '\n'
    printf 'Usage: %s -h | --help ]\n' "$0"
    printf '       %s OUTPUT INPUT1 .. INPUTn\n' "$0"
    printf '\n'
    printf 'Inputs may be audio mp3 or MPEG media files.\n'
    printf '\n'
    exit 1
fi

output="$1"
shift 1
ulimit -n hard

inputs="$(printf '%s|' "${@}")"
inputs="${inputs%|}"

ffmpeg -i "concat:$inputs" -codec copy "$output"
retval=$?

if [ $retval -ne 0 ]; then
    rm -f "$output"
    echo "Failed!"
    exit $retval
fi

# To remove all inputs now, uncomment the following line:
# rm -f "${@}"
echo "Success."
exit 0

私はMPEGを使用しているので、上記は-codec copymp3-acodec copyオーディオファイルだけでなく、あらゆる種類のMPEGファイルに適用する必要があります。

おすすめ記事