printing bad video files with xargs - bash

I use
find . -name "*.mp4" -print0 | xargs -0 -I $ bash -c "ffmpeg -v error -xerror -i $ -f null - || echo $"
to go over a directory and print bad video files (as ffmpeg sees it)
if I run it in a directory with only mp4 files, it will print the name of file - but, if I run it on the parent folder (a folder with many folders, each has mp4 files) I only get $ being echoed
What am I doing wrong?

With GNU Parallel it looks like this:
find . -name "*.mp4" -print0 |
parallel -0 "ffmpeg -v error -xerror -i {} -f null - || echo {}"
It is tested with filename containing ', " and space.

Related

FFprobe to recursively search files to output to csv

I am trying to run a bash script but am encountering some errors.
I want to recursively make the command search through the folder and look for all mp4 files. Then i want it to run the ffprobe command and output it to a csv file in a different location with the filename of the mp4 it ran with .csv
So far i have this
#!/bin/bash
for file in /this/is/directory1/*.mp4; do
ffprobe -show_packets -of csv=print_section=0 $file >> /this/is/directory2/${file}.csv
done
Try this:
find . -type f -name "*.mp4" | xargs -I{} bash -c "ffprobe -show_packets -of csv=print_section=0 {} > /tmp/\$(basename {} | cut -d. -f1).csv"
OR without using xargs
find . -type f -name "*.mp4" -exec bash -c "ffprobe -show_packets -of csv=print_section=0 {} > /tmp/\$(basename {} | cut -d. -f1).csv" ';'
Change the path of directory output file in the command above.

Renaming the output file name from ffmpeg when using find and xargs

I am trying to rename the output files that are coming out of ffmpeg processes that I have spawned using find and xargs. I have a directory of files that I would like to convert to a certain format and all those files should ultimately be named .mov. So I am filtering out .mp4 & .mov files and then using xargs to pass it on to ffmpeg.
Suppose there are files such as abc.mp4, abcd.mp4, abcde.mp3, bcd.mov etc in the current working dir and then I am doing something like this to filter out just the mp4 and mov files and pass it on to ffmpeg for encoding:
find . -type f -name "*.mp4" -o -name "*.mov" | xargs -n 1 -p 5 -I '{}' ffmpeg -i '{}' ....... $PWD/{}"_h264.mov"
This will do what I want ffmpeg to do but it will name the files like
abc.mp4_h264.mov,abcd.mp4_h264.mov,bcd.mov_h264.mov
What I would ideally like to achieve is to name the output files as
abc_h264.mov,abcd_h264.mov,bcd_h264.mov
I am not getting any sparks in my brain on how to do that at the place where I specify the output files of ffmpeg. I know that I can call basename command using xargs like this
find . -type f -name "*.mp4" -o -name "*.mov" | xargs -n 1 basename | rev | cut -d . -f 2 | rev
and extract the filename without the extension but if i use that then how can I pass it on to ffmpeg as the input file because it would have lost the extension when it comes out of xargs and ffmpeg will throw an error.
Could anyone help me achieve this in one go where I can specify what 'basename' is doing but where I am specifying the output file name of ffmpeg please?
Thanks very much for any help that you can provide. Really appreciate the community.
Would you please try the following:
find . -type f -name "*.mp4" -o -name "*.mov" | xargs -I {} -n 1 -P 5 bash -c 'org="{}"; new="$PWD/${org%.*}_h264.mov"; ffmpeg -i "$org" {options} "$new"'
But it is not efficient for spawning bash command as a subprocess
multiple times. If you do not have a specific reason to use find
and xargs, it will be simpler to say:
for org in *.mp4 *.mov; do
new="$PWD/${org%.*}_h264.mov"
ffmpeg -i "$org" {options} "$new"
done

Use parameter expansions in a command run from "find | xargs" to prevent output overwriting

I have this bash script that is looking for mp4 files in subfolders with certain names and saves frames of those videos as jpeg.
#!/bin/bash
find ../folder -type f -iname '*C00*.mp4' | xargs -I %% ffmpeg -i %% -vf fps=1 -q:v 3 "../frames/_${i%.*}_frame%d.jpg"
The problem is that everytime the script finishes one video the .jepg output files of the next videos are overwriting the existing ones.
How can I prevent that?
Here's a quick stab which creates a directory with the same name as the input file with any .mp4 extension trimmed off.
#!/bin/bash
find ../folder -type f -iname '*C00*.mp4' -print0 |
xargs -r0 sh -c 'for f; do
d="../frames/${f%.[Mm][Pp]4}"
mkdir "$d" || { echo "$d already exists" >&2; exit 123; }
ffmpeg -i "$f" -vf fps=1 -q:v 3 "$d/frame%d.jpg"
done' _

Find files and HandBrakeCLI convert in a single line

Not sure if this is possible...
I'm trying to write a terminal command (linux) that would find all video files with a specific extension and then convert them using HandBrakeCLI
I have the first half of that down:
find . -type f -name "*.avi*" -exec
And I have a working HandBrakeCLI command:
HandBrakeCLI -i file.mkv -o file2.mkv -e x265 --vfr -q 20 --all-audio --all-subtitles
What I have been unable to figure out is how to insert the file name/path for the files found in the find into the file.mkv and then output the converted file with the same file name but in an mkv format.
Is it possible to do this in one line or do I need to break this out in a bash script?
As a one-liner, try something like:
find . -type f -name "*.avi" -print0 | perl -pe 's/\.avi\0/\0/g' | xargs -0 -I% HandBrakeCLI -i %.avi -o %.mkv -e x265 --vfr -q 20 --all-audio --all-subtitles
-print0 option in find prints the filename on the standard output, followed by a null character.
The following perl snippet removes the .avi extention to supply the basename to xargs.
-I% option in xargs replaces "%" with names read from standard input.

error while passing files in lame to convert wav into mp3 using sed

ls -1 | xargs --verbose -I{} basename {} \
| sed 's/\.[^.]*$//' \
| xargs -I{} lame {}.* {}.wav
Using this code to convert all the wav files in the folder to mp3 throws a error:
xargs : lame : No such file or directory
Try this:
find . -type f -name "*.wav" -exec bash -c 'mv $0 ${0/\.wav/\.mp3}' {} \;
find - will recursively find for a file type starting current directoy with name like *.wav
-exec will move file with .wav extension to .mp3.
why not a loop instead of multiple xargs ?
LameApp="/YourAppPath/lame.exe"
ls | while read WavFileWExt
do
"${LameApp}" "${WavFileWExt%.*}.mp3" "${WavFileWExt}"
done

Resources