Bash脚本生成的PNG文件名含?4,如何提取视频名中的首个数字?
Hey there, let's sort out this filename problem you're having. The issue with your current script is that grep -o -E '[0-9]+' matches all sequences of digits in the filename—including the 4 from .mp4. Since grep -o prints each match on a new line, your number variable ends up holding two values separated by a newline (like 1 and 4), which shows up as ? in the final PNG filename.
Here are a few ways to fix this and only grab the first set of digits from your video filenames:
Option 1: Tweak the grep Command to Get Only the First Match
Modify the line where you extract the number to keep just the first match from grep:
number=$(echo "$i" | grep -o -E '[0-9]+' | head -n 1)
The head -n 1 command will take only the first line of grep's output, which is the number from your video filename (e.g., 1 from video1.mp4), ignoring the 4 from .mp4.
Option 2: Use Bash Built-in String Handling (More Efficient)
Instead of calling an external tool like grep, you can use Bash's built-in features to extract the number—this is faster and avoids extra processes.
If your video filenames only have single-digit numbers (like video1.mp4, video2.mp4), you can do:
number=${i//[^0-9]/} # Remove all non-digit characters number=${number:0:1} # Keep only the first character (the video number)
If you might have multi-digit numbers (like video123.mp4), use a regex match directly in Bash:
if [[ $i =~ ([0-9]+) ]]; then number=${BASH_REMATCH[1]} fi
This captures the first continuous sequence of digits, so it'll never pick up the 4 from .mp4.
Full Modified Script
Here's the complete script using the regex match method (my recommendation for flexibility):
for i in *.mp4; do [ -f "$i" ] || break if [[ $i =~ ([0-9]+) ]]; then number=${BASH_REMATCH[1]} name="frame${number}.png" ffmpeg -i "$i" -ss 00:01:00.000 -vframes 1 "$name" fi done
Bonus Tips
- To make ffmpeg run quietly (without all the banner and debug output), add
-hide_banner -loglevel errorto the command:ffmpeg -hide_banner -loglevel error -i "$i" -ss 00:01:00.000 -vframes 1 "$name" - If you want to process videos in numerical order (instead of the default filename sort), you can use:
Thefor i in $(ls -v *.mp4); do # Same processing logic as above donels -vcommand sorts filenames in "version order", sovideo1.mp4comes beforevideo10.mp4.
内容的提问来源于stack exchange,提问作者Duck

