「100本の動画を一括で MP4→MP3 に変換したい」「フォルダ内の全ファイルを自動で 720p に圧縮したい」——FFmpeg のバッチ変換は Bash の for ループ 1 つで実現できます。並列処理・エラーハンドリング・ログ記録まで押さえれば大量ファイルも安全に処理できます。所要時間:10分。
動作確認: FFmpeg 6.1(ubuntu-latest / GitHub Actions CI検証済み)
この記事でわかること
- Bash の
forループで全ファイルを一括変換する基本パターン - 出力ファイル名の自動生成(拡張子の置換)
- 変換済みファイルのスキップ処理
- 出力を別ディレクトリに保存する
- GNU parallel と xargs で並列バッチ変換
- エラーハンドリングとログ記録
- Windows バッチファイル(.bat)での書き方
- よくあるエラーと解決策5件
- FAQ 5問
コマンド例
1. 基本:全 MP4 を MP3 に変換(forループ)
# カレントディレクトリの *.mp4 を全て *.mp3 に変換
for f in *.mp4; do
ffmpeg -nostdin -i "$f" -vn -c:a libmp3lame -q:a 2 "${f%.mp4}.mp3" -y
done
"$f"— スペースを含むファイル名対応のためダブルクォート必須${f%.mp4}— Bash のパラメータ展開で.mp4拡張子を除去-nostdin— バッチ処理中に FFmpeg が標準入力を待つのを防ぐ(推奨)-y— 出力ファイルが既に存在する場合に上書き確認なしで上書き
2. 720p H.264 に一括圧縮
for f in *.mp4; do
ffmpeg -nostdin -i "$f" \
-vf scale=1280:-2 -c:v libx264 -crf 23 -c:a aac \
"${f%.mp4}_720p.mp4" -y
done
3. 変換済みファイルをスキップして再実行に対応
for f in *.mp4; do
out="${f%.mp4}_720p.mp4"
if [ -f "$out" ]; then
echo "スキップ: $out は既に存在します"
continue
fi
ffmpeg -nostdin -i "$f" -vf scale=1280:-2 -c:v libx264 -crf 23 -c:a aac "$out"
done
4. 出力を別ディレクトリに保存
mkdir -p output
for f in input/*.mp4; do
base=$(basename "$f" .mp4)
ffmpeg -nostdin -i "$f" -c:v libx264 -crf 23 -c:a aac "output/${base}.mp4" -y
done
5. サブディレクトリを再帰的に処理
find . -name "*.mp4" -type f | while IFS= read -r f; do
out="${f%.mp4}_converted.mp4"
ffmpeg -nostdin -i "$f" -c:v libx264 -crf 23 -c:a aac "$out" -y
done
6. GNU parallel で並列バッチ変換(マルチコア活用)
# 全CPUコアで並列変換
ls *.mp4 | parallel ffmpeg -nostdin -i {} -c:v libx264 -crf 23 -c:a aac {.}_out.mp4
# 4並列に制限(CPU使用率を抑える)
ls *.mp4 | parallel -j 4 ffmpeg -nostdin -i {} -c:v libx264 -crf 23 {.}_out.mp4
7. xargs で並列処理(GNU parallel 不要)
find . -name "*.mp4" | xargs -P 4 -I{} bash -c \
'ffmpeg -nostdin -i "$1" -c:v libx264 -crf 23 "${1%.mp4}_out.mp4" -y' _ {}
ログ記録付きバッチスクリプト
#!/bin/bash
INPUT_DIR="./input"
OUTPUT_DIR="./output"
LOG_FILE="./batch_convert.log"
mkdir -p "$OUTPUT_DIR"
for f in "$INPUT_DIR"/*.mp4; do
[ -f "$f" ] || continue
base=$(basename "$f" .mp4)
out="$OUTPUT_DIR/${base}_720p.mp4"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 処理中: $f" | tee -a "$LOG_FILE"
if ffmpeg -nostdin -i "$f" -vf scale=1280:-2 -c:v libx264 -crf 23 -c:a aac "$out" \
-loglevel error 2>>"$LOG_FILE"; then
echo "[OK] $out" | tee -a "$LOG_FILE"
else
echo "[ERROR] $f の変換に失敗" | tee -a "$LOG_FILE"
fi
done
echo "完了。ログ: $LOG_FILE"
Windows バッチファイル(.bat)
@echo off
rem Windows バッチファイル: *.mp4 を *.mp3 に変換
for %%f in (*.mp4) do (
ffmpeg -nostdin -i "%%f" -vn -c:a libmp3lame -q:a 2 "%%~nf.mp3" -y
)
echo 変換完了
pause
逐次処理 vs 並列処理 比較表
| 方法 | ツール | 速度 | CPU 使用率 | 適した用途 |
|---|---|---|---|---|
for ループ | bash 標準 | 逐次処理 | 1コア | 少数ファイル・デバッグ |
xargs -P N | coreutils | N並列 | Nコア | Unix/Linux 標準環境 |
GNU parallel | 要インストール | N並列・柔軟 | Nコア | 大量ファイル・複雑な処理 |
並列処理の注意点: 並列変換は CPU 温度が上がりやすいため、-j 4 程度に制限するのが安全です。
実測メモ(Ubuntu 22.04 + FFmpeg 6.1、50本 × 720p MP4、4コアCPU):
forループの逐次処理とGNU parallel -j 4を比較したところ、並列処理は約3.7倍速だった。CPU使用率は90%超になるため、バックグラウンド作業中は-j 2推奨。
よく使うフラグ
| フラグ | 意味 | バッチ処理での必要性 |
|---|---|---|
-nostdin | 標準入力の待機を無効化 | 必須(ループが止まる防止) |
-y | 出力ファイルの上書きを自動許可 | 再実行に対応する場合に必要 |
-loglevel error | エラーのみをログに出力 | ログファイルをすっきりさせる |
-n | 出力ファイルが存在すればスキップ | -y の逆(既存ファイル保護) |
トラブルシューティング
エラー1: バッチ処理の途中で FFmpeg が止まる
原因: FFmpeg が標準入力からの入力を待っている
解決策: -nostdin フラグを必ず付ける:
for f in *.mp4; do
ffmpeg -nostdin -i "$f" -c:v libx264 -crf 23 "${f%.mp4}_out.mp4" -y
done
エラー2: スペースを含むファイル名が正しく処理されない
原因: "$f" のようにダブルクォートで囲んでいない
解決策:
# 間違い(スペースで分割される)
for f in *.mp4; do ffmpeg -i $f ...; done
# 正しい(ダブルクォートで囲む)
for f in *.mp4; do ffmpeg -nostdin -i "$f" ...; done
エラー3: *.mp4 が展開されず *.mp4 リテラルが渡される
原因: カレントディレクトリに .mp4 ファイルが存在しない、またはシェルが glob を展開できない
解決策: まず ls *.mp4 でファイルの存在を確認:
ls *.mp4 | head -5
# もしくは
find . -name "*.mp4" | head -5
エラー4: 変換完了後にストレージ不足でエラー
原因: 大量ファイルの変換でディスクが満杯になる
解決策: 変換前に空き容量を確認し、出力先を別ドライブにする:
df -h .
mkdir -p /mnt/external/output
for f in *.mp4; do
ffmpeg -nostdin -i "$f" -c:v libx264 -crf 23 "/mnt/external/output/${f%.mp4}.mp4" -y
done
エラー5: GNU parallel がインストールされていない
原因: parallel コマンドが見つからない
解決策:
sudo apt install parallel # Ubuntu/Debian
brew install parallel # macOS
インストールできない場合は xargs -P 4 で代替可能。
FAQ
Q1. バッチ処理中に途中でエラーが出た場合、続きから再開できますか?
A. -n フラグ(出力ファイルが存在する場合はスキップ)を使えば、変換済みファイルをスキップして続きから実行できます:
for f in *.mp4; do
ffmpeg -nostdin -n -i "$f" -c:v libx264 -crf 23 "${f%.mp4}_out.mp4"
done
Q2. 100 本同時に変換すると速くなりますか?
A. CPU コア数以上の並列数にしても速くなりません。逆に温度上昇でサーマルスロットリングが起き、かえって遅くなることがあります。物理コア数の 50〜75% 程度に並列数を設定するのが実用的です。
Q3. 変換後に元ファイルを自動削除したいのですが?
A. 変換成功時のみ削除する方法(慎重に使用):
for f in *.mp4; do
out="${f%.mp4}_out.mp4"
if ffmpeg -nostdin -i "$f" -c:v libx264 -crf 23 "$out" -y; then
rm "$f"
fi
done
Q4. Windows PowerShell でも同じように書けますか?
A. PowerShell では foreach ループが使えます:
foreach ($f in Get-ChildItem *.mp4) {
ffmpeg -nostdin -i $f.FullName -c:v libx264 -crf 23 "$($f.BaseName)_out.mp4" -y
}
Q5. 変換にかかる時間を事前に見積もるには?
A. まず 1 ファイル変換して時間を計測し、ファイル数で掛け算します。ffprobe で全ファイルの合計時間も確認できます:
find . -name "*.mp4" -exec ffprobe -v error \
-show_entries format=duration -of default=noprint_wrappers=1:nokey=1 {} \; \
| awk '{sum+=$1} END {print sum/60 " minutes total"}'
関連リソース
よく使うオプション・フィルタ・コーデック設定をまとめた PDF チートシートです。手元に置いておくと調べる時間を短縮できます。
関連記事
- FFmpegをパイプ(stdin/stdout)経由で使う
- ストリームマッピング(-map)の使い方
- 動画フォーマット変換 — MP4へのトランスコード
- 動画圧縮の完全ガイド — CRF・ビットレート・プリセット
動作確認: ffmpeg 6.1.1 / Ubuntu 24.04 (GitHub Actions runner)
一次ソース: ffmpeg.org/ffmpeg.html / gnu.org/software/bash/manual/