user2950602
user2950602

Reputation: 395

Spaces in directory name Bash

I'm new to bash and I'm working on script that traverses the tar.gz file archive and in each file changes a string specified to an another string. Args of script: name of archive, searched string, target word. My problem is that when archive name contains a space (e.g. I run script with following args: > change_strings.sh "/tmp/tmp.m7xYn5EQ2y/work/data txt" a A) I have following error: on line if [ ! -f $filename ] ; then [: data: binary operator expected, dirname: extra operand `txt'. Here is my code:

  #!/bin/bash 
  filename="${1##*/}"
  VAR="$1"
  DIR=$(dirname ${VAR})
  cd "$DIR"


if [ ! -f $filename ] ; then
echo "no such archive" >&2
exit 1
fi


if ! tar tf $filename &> /dev/null; then
echo "this is not .tar.gz archive" >&2
exit 1
fi


dir=`mktemp -dt 'test.XXXXXX'`
tar -xf $filename -C $dir  #extract archive to dir
cd $dir #go to argument directory

FILES=$dir"/*"

for f in $FILES
do
sed -i "s/$2/$3/g" "$f"
done

tar -czf $filename * #create tar gz archive with files in current directory
mv -f $filename $cdir"/"$filename #move archive
rm -r $dir #remove tmp directory

Upvotes: 0

Views: 1156

Answers (2)

that other guy
that other guy

Reputation: 123410

Welcome to stackoverflow!

For the convenience of current and future readers, here's a small, self contained example showing the problem:

filename="my file.txt"
if [ ! -f $filename ]
then
    echo "file does not exist"
fi

Here's the output we get:

$ bash file
file: line 2: [: my: binary operator expected

And here's the output we expected to get:

file does not exist

Why are they not the same?


Here's what shellcheck has to say about it:

$ shellcheck file
In file line 2:
if [ -f $filename ]
        ^-- SC2086: Double quote to prevent globbing and word splitting.

and indeed, if we double quote it, we get the expected output:

$ cat file
filename="my file.txt"
if [ ! -f "$filename" ]
then
    echo "file does not exist"
fi

$ bash file
file does not exist

You should be double quoting all your variables.

However, you have to take care with $FILES because it contains a glob/wildcards that you want to expand along with potential spaces that you don't want to wordsplit on. The easiest way is to just not put it in a variable and instead write it out:

for f in "$dir"/*
do
  ...

Upvotes: 1

yxre
yxre

Reputation: 3704

The proper way to handle this is to surround your variables with double quotes.

var=/foo/bar baz
CMD $var # CMD /foo/bar baz

The above code will execute CMD on /foo/bar and baz

CMD "$var"

This will execute CMD on "/foo/bar baz". It is a best practice to always surround your variables with double quotes in most places.

Upvotes: 1

Related Questions