1

I have many folders with .mp4 files. I wrote a script that takes the mp4 files and converts them into 1 jpeg image per frame. Critically, the output of this script (retained file name, with _frame number appended to the end) goes into a newly created folder with the file basename:

#!/bin/bash
for f in *.mp4; do mkdir -p "${f%.*}" && ffmpeg -i ${f} -start_number 000 "${f%.*}/${f}_%03d.jpg"; done

I can run this for every parent folder one at a time no problem but I would like to just run it once and get it to run recursively.

I changed the code to:

#!/bin/bash
for f in *.mp4/; do mkdir -p "${f%.*}" && ffmpeg -i ${f} -start_number 000 "${f%.*}/${f}_%03d.jpg"; done

and tried playing with the mkdir part (by adding ./) but no matter what I do, I get the following error.

mkdir: cannot create directory ‘*’: Invalid argument

Is there anything I need to do to allow mkdir to create the appropriate new folders in their respective subfolders?

The file structure is as follows:

parent folder
    └── videos_1
        ├── videos_1_basename_1.mp4
        └── videos_2_basename_2.mp4
    └── videos_2
        ├── videos_2_basename_1.mp4
        └── videos_2_basename_2.mp4
.sh script

3 Answers 3

5

You can use the globstar bash option to recurse in sub-directories and also the nullglob option such that the pattern expands as null instead of itself (the reason for your error as explained in another answer):

#!/usr/bin/env bash

shopt -s globstar nullglob
for f in **/*.mp4; do
  d=${f%.mp4}
  b=$(basename -s.mp4 "$f")
  if mkdir -p "$d"; then
    ffmpeg -i "$f" -start_number 000 "$d/${b}_%03d.jpg"
  else
    printf 'could not mkdir %s\n' "$d"
  fi
done

Note: for a video named:

videos_1/videos_1_basename_1.mp4

this will create JPEG files named:

videos_1/videos_1_basename_1/videos_1_basename_1_000.jpg
videos_1/videos_1_basename_1/videos_1_basename_1_001.jpg
...

If you really want to keep the .mp4 extension in the names:

videos_1/videos_1_basename_1/videos_1_basename_1.mp4_000.jpg
...

just remove the -s.mp4 option of basename.

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for your answer! I tried and got the error - Could not open file : videos_1/videos_1_basename/videos_1_basename.mp4_000.jpg av_interleaved_write_frame(): Input/output error. Do you have any ideas what might cause this?
Was the sub-directory properly created?
Yes it was indeed
Strange. Did you test the ffmpeg command manually? Are you under Windows and does it expect backslashes instead of slashes in paths?
I'm on Ubuntu 20.04. I tested the following command manually (within the folder) and it worked perfectly. for f in .mp4; do mkdir -p "${f%.}" && ffmpeg -i ${f} -start_number 000 "${f%.*}/${f}_%03d.jpg"; done - I just double checked to see if it was written correctly in my question, and seems to be
|
1

Suggesting to use find command to get all *.mp4 under current directory.

#!/bin/bash
for currFile in $(find -name "*.mp4"); do
  currDir="${currFile %.mp4}"
  mkdir -p "$currDir"
  ffmpeg -i "$currFile " -start_number 000 "$currDir/${currFile}_%03d.jpg"
done

Comments

0

*.mp4/ would, due to the appended /, expand to all directories where the name ends in .mp4. If you don't have directories with such a name, you don't get any wildcard expansion. f is therefore set to the string *.mp4/ and ${f%.*} yields a lone *, as you can try by yourself on the command line. It seems that mkdir refuses the creation of directory with such a weird name; I would consider this a feature instead of a bug.

There is no recursion in your code with respect to the directories. You could do a

for f in videos_*/*.m4a

inside your parent folder. Of course f will then also contain the name of the respective subdirectory (for instance videos_1/videos_1_basename_1.m4a), and you have to adapt your script to this fact.

1 Comment

Thank you for your answer! I added this and got the exact same error as the answer from Renaud. I'm confused because there is no such error if I have the .sh file and run it within each folder individually. Do you have any ideas for what causes that error?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.