Is driving me crazy to get the way to execute a command into a Bash Script. This is the code:
read -ep "Select a video: " path
path=$(echo "$path" | sed -e 's|~|'"${HOME}"'|g' -e 's/ /\\ /g')
echo $path
duracion=$(ffprobe -i $path -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1)
echo $duracion
I ask for a video name. I replace a posible ~ for the $HOME and replace any space in the folder/files names with a \space But when I try to get the video duration I am getting a error if any name has an space. If I execute the ffprobe command directly in a Terminal with the path resulting with the conversion I get the duration. But If I execute the bash script I get an error. Can you help me to get the video duration with the script? Thank you very much
CodePudding user response:
There is a lovely service called shellcheck
Here is the output from your script in shellcheck:
$ shellcheck myscript
Line 3:
read -ep "Select a video: " path
^-- SC2162 (info): read without -r will mangle backslashes.
Line 5:
echo $path
^-- SC2086 (info): Double quote to prevent globbing and word splitting.
Did you mean: (apply this, apply all SC2086)
echo "$path"
Line 6:
duracion=$(ffprobe -i $path -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1)
^-- SC2086 (info): Double quote to prevent globbing and word splitting.
Did you mean: (apply this, apply all SC2086)
duracion=$(ffprobe -i "$path" -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1)
Line 7:
echo $duracion
^-- SC2086 (info): Double quote to prevent globbing and word splitting.
Did you mean: (apply this, apply all SC2086)
echo "$duracion"
So most of your errors are result of not quoting variable subjecting them to word splitting, glob expansion, etc.
So in the line $(ffprobe -i $path -v quiet ...)
, without quotes, a value for $path
with a space becomes more than one argument after being split by the shell. Now you have too many arguments and wrong file names passed to ffprobe
.
Bottom line: USE QUOTES
And learn more about quoting HERE
When I am writing a shell script, I always use quotes just as habit even if I know the type of content in the variable does not need them. If I don't use quotes, I usually comment on why I didn't since there are times you want to use word splitting or glob expansion.
For example, you don't want to quote here:
$ echo *.txt # get all files with .txt in current directory
1 2.txt 1.txt 2.txt # there are 3 files with .txt 1 has space
Or here:
$ printf "%s\n" *.txt
1 2.txt
1.txt
2.txt
If you do use quotes, it means something different:
$ echo "*.txt"
*.txt
$ printf "%s\n" "*.txt"
*.txt
Another example:
Unquoted - the *
glob is expanded:
$ for fn in *.txt; do echo "$fn"; done
1 2.txt
1.txt
2.txt
Quoted -- the *
is treated as a literal:
$ for fn in "*.txt"; do echo "$fn"; done
*.txt
And "$fn"
is quoted since with it being an argument to echo
it is subject to globbing and word splitting again!
(Both the loop and and the printf
are more interesting. As the result of something, and not the argument to something, no quotes are needed...)
A better way to expand a variable into the home directory in Bash is to use parameter expansion btw:
$ fn='~/file.txt'
$ fn="${fn/#\~/$HOME}"
$ echo "$fn"
/Users/dawg/file.txt