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ファイルのリストをサブリスト(順番に保持)に分割し、徐々に削除し、sox
bashスクリプトから不要なファイルを削除する最善の方法は何ですか?
答え1
まず、リストを Bash 配列として収集します。ファイルが現在のディレクトリにある場合は、次のものを使用できます。
files=(prefix_????.mp3)
または、検索と並べ替えを使用できます。
IFS=$'\n' ;
files=($(find . -name 'prefix_*.mp3' printf '%p\n' | sort -d))
この設定はIFS
Bash に改行文字でのみ分割するよう指示します。ファイル名とディレクトリ名にスペースが含まれていない場合は省略できます。
または、ファイルからファイル名を読み取ることができます(たとえば、filelist
1行に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
ループは早期に終了します。それ以外の場合は、処理されたバッチの姓を出力します。
if
for コマンドを使用して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 copy
mp3-acodec copy
オーディオファイルだけでなく、あらゆる種類のMPEGファイルに適用する必要があります。
答え2
(明確さを高め、より安全に編集しました)
ファイルの順序にスペースがない場合、この方法は機能します。LAST=0
シーケンスの最後の4桁の数字に置き換えてください。あなたは残るでしょうscript_name_output.mp3
。
# make a backup in case anything goes wrong
mkdir backup && cp *.mp3 backup
# enter last 4-digit number in the file sequence
LAST=0
LASTNN__=$(echo ${LAST:0:2})
LAST__NN=$(echo ${LAST:2:2})
# sox 100 files at a time
for i in $(seq -f "%02g" 0 $((--LASTNN__))); do
LIST=$(paste -sd' ' <(seq -f "prefix_$i%02g.mp3" 0 99));
sox $LIST script_name_output_$i.mp3;
done
# sox the last group
LAST_LIST=$(paste -sd' ' \
<(seq -f "prefix_${LASTNN__}%02g.mp3" 0 $LAST__NN))
sox $LAST_LIST script_name_output_${LASTNN__}.mp3
# concatenate all the sox'ed files
OUTPUT_LIST=$(paste -sd' ' \
<(seq -f "script_name_output_%02g.mp3" 0 $LASTNN__))
sox $OUTPUT_LIST script_name_output.mp3
# delete the intermediate files
rm $OUTPUT_LIST
# delete input files if everything worked
rm prefix_*.mp3
答え3
ファイル記述子の制限を増やすことができます。
ulimit -n 11000
一般ユーザーとして、この制限を次に増やすことができます。硬い限界。ulimit -Hn
現在のハード制限を確認してください。
ルート以外のプロセスはハード制限を増やすことはできません(これは管理者が通常のユーザーがシステムリソースを乱用しないように設定したものです)。スーパーユーザーアクセス権がある場合は、sudo
スーパーユーザーではなく新しいシェルを起動し、次の方法でハード制限とソフト制限を増やすことができます。
sudo HOME="$HOME" zsh -c 'ulimit -HSn 100000; USERNAME=$SUDO_USER; zsh'
またはsoxコマンド:
sudo HOME="$HOME" zsh -c 'ulimit -HSn 100000; USERNAME=$SUDO_USER
sox prefix_*.mp3 script_name_output.mp3'
prlimit
Linuxでは、rootとして次のコマンドを呼び出してシェル(およびそのサブシェル)の制限を増やすこともできます。
bash-4.3$ ulimit -n
1024
bash-4.3$ ulimit -Hn
65536
bash-4.3$ sudo prlimit --nofile=100000:100000 --pid="$$"
bash-4.3$ ulimit -Hn
100000
bash-4.3$ ulimit -n
100000
それ以外の場合は、ファイルを347のファイルグループに分割してリンクし、中間ファイルをリンクする2つの手順でこれを実行できます。
そしてzsh
:
intermediate_concat() sox "$@" intermediate.$((++n)).mp3
autoload zargs
n=0
zargs -n 347 prefix_*.mp3 -- intermediate_concat
sox intermediate.*.mp3(n) script_name_output.mp3