Home > Software engineering >  Bash Script error when files or folder has space in the name
Bash Script error when files or folder has space in the name

Time:12-20

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
  • Related