ffmpeg doesn't accept input in script - linux

this is a beginner's question but i can't figure out the answer after looking into it for several days:
I want ffmpeg to extract the audio portion of a video and save it in an .ogg container. If i run the following command in terminal it works as expected:
ffmpeg -i example.webm -vn -acodec copy example.ogg
For convenience, i want to do this in a script. However, if i pass a variable to ffmpeg it apparently just considers the first word and produces the error "No such file or directory".
I noticed that my terminal escapes spaces by a \ so i included this in my script. This doesn't solve the problem though.
Can someone please explain to me, why ffmpeg doesn't consider the whole variable that is passed to it in a script while working correctly when getting passed the same content in the terminal?
This is my script that passes the filename with spaces escaped by \ to ffmpeg:
#!/bin/bash
titelschr=$(echo $# | sed "s/ /\\\ /g")
titelohne=$(echo $titelschr | cut -d. -f 1)
titelogg=$(echo -e ${titelohne}.ogg)
ffmpeg -i $titelschr -vn -acodec copy $titelogg
Thank you very much in advance!

You need to quote variable expansions, try this :
#!/usr/bin/env bash
titelschr=$1
titelogg="${titelschr%.*}.ogg"
ffmpeg -i "$titelschr" -vn -acodec copy "$titelogg"
call with :
bash test.sh "Some video file.mp4"
This way, you don't need to escape spaces.

Related

Is there problem with 'read' command in Bash, or in Bash itself when using multiprocessing, or may be I make some mistake? [duplicate]

This question already has answers here:
While loop stops reading after the first line in Bash
(5 answers)
Closed 2 years ago.
I have three .wav files in my folder and I want to convert them into .mp3 with ffmpeg.
I wrote this bash script, but when I execute it, only the first one is converted to mp3.
What should I do to make script keep going through my files?
This is the script:
#!/bin/bash
find . -name '*.wav' | while read f; do
ffmpeg -i "$f" -ab 320k -ac 2 "${f%.*}.mp3"
done
Use the -nostdin flag to disable interactive mode,
ffmpeg -nostdin -i "$f" -ab 320k -ac 2 "${f%.*}.mp3"
or have ffmpeg read its input from the controlling terminal instead of stdin.
ffmpeg -i "$f" -ab 320k -ac 2 "${f%.*}.mp3" </dev/tty
See the -stdin/-nostdin flags in the ffmpeg documentation
If you do need find (for looking in subdirectories or performing more advanced filtering), try this:
find ./ -name "*.wav" -exec sh -c 'ffmpeg -i "$1" -ab 320k -ac 2 "$(basename "$1" wav).mp3"' _ {} \;
Piping the output of find to the while loop has two drawbacks:
It fails in the (probably rare) situation where a matched filename contains a newline character.
ffmpeg, for some reason unknown to me, will read from standard input, which interferes with the read command. This is easy to fix, by simply redirecting standard input from /dev/null, i.e. find ... | while read f; do ffmpeg ... < /dev/null; done.
In any case, don't store commands in variable names and evaluate them using eval. It's dangerous and a bad habit to get into. Use a shell function if you really need to factor out the actual command line.
No reason for find, just use bash wildcard globbing
#!/bin/bash
for name in *.wav; do
ffmpeg -i "$name" -ab 320k -ac 2 "${name%.*}.mp3"
done

What is the problem with this python 3 script

I made a script for compressing videos
import ffmpeg
import subprocess
result = subprocess.run("C:\\ffmpeg\\bin\\ffmpeg.exe"['ffmpeg -i output.mp4 -b 800k output.mp4'])
print(result)
When I run this an error will come like this-
result = subprocess.run("C:\\ffmpeg\\bin\\ffmpeg.exe"['ffmpeg -i output.mp4 -b 800k output.mp4'])
TypeError: string indices must be integers
What is the solution?
This appears to be malformed:
subprocess.run("C:\\ffmpeg\\bin\\ffmpeg.exe"['ffmpeg -i output.mp4 -b 800k output.mp4'])
I'm pretty sure you just want this:
result = subprocess.run(["C:\\ffmpeg\\bin\\ffmpeg.exe", "-i", "output.mp4", "-b", "800k", "output.mp4"])
Or perhaps just this:
result = subprocess.run("C:\\ffmpeg\\bin\\ffmpeg.exe -i output.mp4 -b 800k output.mp4")
Also, not sure if it's a good idea to have your input file and output file, output.mp4 be the same.
Well, look at the argument you tried to pass. I've insert a line feed to help reading:
"C:\\ffmpeg\\bin\\ffmpeg.exe"
['ffmpeg -i output.mp4 -b 800k output.mp4']
The first line is a string. You followed that with a bracket. What comes next must be a subscript for the string. What did you think you were doing?
"C:\\ffmpeg\\bin\\ffmpeg.exe"['ffmpeg -i output.mp4 -b 800k output.mp4']
As #Prune has pointed out, the error occurs as you're indexing the string using another string, which is incorrect. The correct way to pass arguments to subprocess.run is
result = subprocess.run("[C:\\ffmpeg\\bin\\ffmpeg.exe", 'ffmpeg -i output.mp4 -b 800k output.mp4'])
If you want to add more arguments, you can do so using positional arguments.

why 'read' command in shell script is missing initial characters? [duplicate]

This question already has answers here:
While loop stops reading after the first line in Bash
(5 answers)
Closed 3 years ago.
I have the following shell script and it is missing some initial characters (it misses initial couple of characters, so far in my observation) from each line except the first line.
And this happens only when I use the ffmpeg command. Otherwise, it is fine. But this command does the actual task in this script.
Why is it so and what is the fix?
#!/bin/bash
while read line; do
printf "%s\n" "$line"
ifile=$line
printf "%s\n" "$ifile"
ofile=abc_$line
printf "%s\n" "$ofile"
############### Problem is the following command: ##########
ffmpeg -y -i $ifile -c:v libx264rgb -b:v 512k -bf 0 -pix_fmt rgb24 -r 25 -strict -2 $ofile
##########rest is fine##########
echo $ifile
done < file_list
This is pretty well explained in this post I'm reading a file line by line and running ssh or ffmpeg, only the first line gets processed!. When reading a file line by line, if a command inside the loop also reads stdin, it can exhaust the input file. In your case ffmpeg also reads from stdin.
The most common symptom of this is a while read loop only running once, even though the input contains many lines. This is because the rest of the lines are swallowed by the offending command. The most common fix for the problem is to close the stdin of the ffmpeg by doing < /dev/null
ffmpeg -y -i "$ifile" -c:v libx264rgb -b:v 512k -bf 0 -pix_fmt rgb24 -r 25 -strict -2 "$ofile" < /dev/null
or use another file descriptor other than standard input
while read -r line <&3; do
ifile="$line"
ofile="abc_${line}"
ffmpeg -y -i "$ifile" -c:v libx264rgb -b:v 512k -bf 0 -pix_fmt rgb24 -r 25 -strict -2 "$ofile"
done 3<file
Or your problem could altogether be a case of the input file having DOS style line endings carried over from a DOS environment. You can check that out by running the file command on the input file (file file_list) which could show CRLF line terminators. In such case do a clean-up of the input file as dos2unix file_list and re-run your script.

How to set and use filename string variables in cmd command line?

I'm trying to run a for loop in cmd that looks like this:
for %f in (*.mp4) do (
set outfile=%f:mp4=mp3%
ffmpeg -i %f -vn -ar 44100 -ac 1 -b:a 32k -f mp3 %outfile%
)
The script is supposed to grab all *.mp4 files, run the ffmpeg command on them, then name the resultant file identical as the mp4 with only the extension changed to *.mp3.
It doesn't work. The output is literally named %outfile%. If I had to guess, there's something wrong with the initialization or calling of the outfile variable. I also thought that perhaps it is a data type issue. %f is perhaps a pointer, not a string, so some kind of string extraction or type conversion is needed.
How can I set and use a filename as a string variable in cmd?
The best way to do it is not to do it. Don't store inside a variable something that can be directly retrieved from the for replaceable parameter.
for %f in (*.mp4) do ffmpeg -i "%f" -vn -ar 44100 -ac 1 -b:a 32k -f mp3 "%~nf.mp3"
The for command replaceable parameter (%f in your case) allow the use of some modifiers (see for /?). %~nf is the name, without extension, of the file being referenced by %f
But, if your only option is to do it, here you can find some ways to deal with the problem.

Passing spaces conteined string to script

I use such small script to convert videos from my SAT receiver to h264/mp3 format.
[maciek#piotr Pobrane]$ cat ./conv_sat_to_clean_ts
#!/bin/bash
ffmpeg -i $1.ts -movflags +faststart -vcodec h264 -acodec mp3 -f mpegts $1-new.ts
The problem is that when I call that script in such way:
./conv_sat_to_clean_ts ./Operacja\ Dunaj.ts
it shows me an error:
./Operacja: No such file or directory
So that means that spaces included in call parameters are ignored and filename is not interpreted correctly.
Is any way to resolve that problem?
Give $1 in double quotes since filename has space.
ffmpeg -i "$1".ts -movflags +faststart -vcodec h264 -acodec mp3 -f mpegts "$1"-new.ts
and run the script without .ts
./conv_sat_to_clean_ts ./Operacja\ Dunaj
or
./conv_sat_to_clean_ts "Operacja Dunaj"
Yes. RBH was right. Now my script looks like this and work properly.
#!/bin/bash
ffmpeg -i "$1" -movflags +faststart -vcodec h264 -acodec mp3 -f mpegts NEW-"$1"
And spaces in filenames (as script call parameter) are interpreted correctly

Resources