Bash error when using quote

Hello.

[LEFT]Someone can it tell me why the following syntax is incorrect. And so how to treat the filenames with spaces.

linux:~ # ls "/usr/NX/var/log/*.log"
ls: cannot access /usr/NX/var/log/*.log: No such file or directory
linux:~ # 

But this one is correct.

[/LEFT]

linux:~ #  ls /usr/NX/var/log/*.log
/usr/NX/var/log/nxd.log  /usr/NX/var/log/nxerror.log  /usr/NX/var/log/nxserver.log
linux:~ #

From a bash script:

CMD="cp -v    \"/$MY_DIR_5_2/*.log\"  \"$MY_ROOT_DIR/$MY_DIR_5_2\" "
echo "COMMAND_5 : $CMD"
eval $CMD

After variables expansion :

linux:~ # cp -v    "/usr/NX/var/log/*.log"  "/root/bin/202_nomachine_4/000_backup_current_config/2014-12-18__12-29-04/usr/NX/var/log"
cp: cannot stat �/usr/NX/var/log/*.log': No such file or directory
linux:~ #

If either the directory source or destination contain space, I must use quote ?

Any help is welcome.

Yes.
* is handled as shell expansion, but if you put it into quotes, it might be taken literary (as in: just as the char it is)
This is also true for REGEX, if you put them into quotes, they will fail.

There are a few exceptions to this:

for ELEMENT in "${ARRAY[*]}"
do
   echo "$ELEMENT"
done

Here, the quotes around the array would be required, if any of the arrays elements contains a space.

In some occasions it is easier to make a list-variable first.

# Defines the variable 'list' as an array
declare -A list   
# Fill the array, exit if it fails
list=$(echo /var/log/*log) || exit 1 
# Copy the files
cp -v "${list[*]}" "/target/dir"

Alternativly, you can create an array also like these:

array1=( one two "t h r e e" four)

array2=( $(ls /var/log/*log) )

array3[0]=one
array3[1]=two
array3[2]="t h r e e"

Hope this helps

1 Like

wildcards in quotes don't expand.

Fortunately, you don't have to quote the entire string.

command "big long path with spaces/"*.ext
1 Like

Do you mean that

cp "big long source path with spaces/*.ext   big long dest path with spaces    

will work ?

That's exactly what I don't mean. If it contains spaces, it must be quoted (or escaped) but you can have parts of the same string inside and outside quotes. You can consider the " character to mean turn off splitting until another " is found, rather than "enclose one literal, individual string".

"this is quoted"this_is_not"this is"this_is_not"but all the same string"*.txt

So your command would be more like:

cp "big long source path with spaces/"*.ext   "big long dest path with spaces"
1 Like

Obviously, the wildcard/star * won't expand within quotes...

You could try

ls "/usr/NX/var/log/"*.log

also try

ls "/dir/with/s p a c e s/log"*.log # note this should list the files, you can't simply substitute ls with cp.

This should work if the source directory and/or source files have no space in the name:

CMD="cp -v    \"/$MY_DIR_5_2/\"*.log  \"$MY_ROOT_DIR/$MY_DIR_5_2\" "

It should work too if the source directory has spaces in the path, but you keep the quotes around it.

If the source directory and/or source files have space in the name, try this (untested)

CMD="ls \"/dir/with/s p a c e s/log\"*.log | while read file; do cp -v \"$file\" \"$MY_ROOT_DIR/$MY_DIR_5_2\"; done "

Hope this helps.

1 Like

Congratulations, you have found a bad script.

Seriously, don't do that. Don't put quotes inside quotes. They are a huge amount of trouble to get back out. Put the programming in program, and the things that vary, inside the variable, and you will have far less trouble and people will be able to understand what your code is meant to do without a debug trace.

1 Like

Thank you everybody for helping.