2

I am trying develop a bash script which processes a list of files which may contain space names.

(I have already consulted Trouble in script with spaces in filename and Why I can't escape spaces on a bash script?, but can not seem to perfect my script.)

Here is my script. The actual process is more complicated which I reduce here to simple file command.

#!/bin/bash

if [ $# -eq 0 ]; then
   echo "Usage is $0 <files to be tested>"
   exit
fi

allfilestobetesed=$@
for filetobetested in "$allfilestobetested"
do
    file "$filetobetested"
done

How do I improve my script?

Masroor
  • 295
  • Are the names with spaces being quoted when invoking the script? – Eric Renouf Oct 23 '15 at 15:03
  • @EricRenouf No. This is mostly * or *.tex or something similar. – Masroor Oct 23 '15 at 15:06
  • The shell will expand them correctly there, so that should be OK I think. – Eric Renouf Oct 23 '15 at 15:09
  • @Masroor you made a mistake in copying what was posted. Use "@" not '"$@"' Also it is generally more helpful to put the set -x inside the script. – rocky Oct 23 '15 at 15:33
  • @rocky I thought that at first too, but that's just how set -x ends up displaying the "$@" part, I tried it locally and saw the same thing, it just turned out to be a typo further down – Eric Renouf Oct 23 '15 at 15:41

3 Answers3

4

You should probably get rid of your allfilestobetested variable if you can:

for filetobetested in "$@"; do
    file "$filetobetested"
done

will expand correctly

Eric Renouf
  • 18,431
  • Funny, this won't work if you run it like this: bash a.sh $(ls -1) (supposing that you save this script as a.sh). – Kira Oct 23 '15 at 17:23
  • 1
    @Kira Right, because then you're getting a string as output from ls -1 and using that string as the arguments to a.sh, which will be subject to word splitting rules. Basically meaning all the spaces will be processed before you start running a.sh. That means you can't do much to fix it from within – Eric Renouf Oct 23 '15 at 17:43
  • But does is strip out the '\n' too? I've tried splitting the output in the loop by line breaks with IFS=$'\n', but with no success =/ – Kira Oct 23 '15 at 18:07
  • 1
    @kira I fear you've set for yourself a very difficult task if you want to try to use ls there. You might want to read http://mywiki.wooledge.org/ParsingLs for a good discussion of why it's going to be very difficult to get it to do what you want. Also, as I noted, if you are setting IFS inside your script that's too late, since bash is doing the word splitting to assign the output of ls to the arguments to the script before the script is invoked. It's too late when you're inside a.sh, the damage is already done so to speak – Eric Renouf Oct 23 '15 at 18:10
2

You were pretty close. First, you got right using $@ instead of $*.

You need to worry about shell expansion so don't use " unnecessarily as happened in the assignment. That will remove the boundaries between tokens. However you do need it around "@_".

So we have:

if [ $# -eq 0 ]; then
   echo "Usage is $0 <files to be tested>"
   exit
fi

for filetobetested in "$@"
do
    file "$filetobetested"
done

Lastly, my bash debugger http://bashdb.sf.net can help you follow stuff like this. Section 1.2 of the bashdb manual describes how to set PS4 to give more information from set -x tracing.

rocky
  • 1,998
  • Thanks, but how does this answer differ from the other answer already posted? – Masroor Oct 23 '15 at 15:17
  • 1
    I started writing it it at the same time as the first answer. It took me longer to write though because I was explaining why the changes. – rocky Oct 23 '15 at 15:28
0

You don't need "$@":

    for filetobetested
    do
        file "$filetobetested"
    done
RobertL
  • 6,780
  • Yes, I do. The file command is not the actual command in the real script, where the files need to be processed individually. – Masroor Oct 24 '15 at 12:59
  • No you don't. My statement has nothing to do with whether you use the file command or not. for xyz in "$@" means exactly the same thing as for xyz with no in clause. From the dash (posix shell) manpage: Omitting in word ... is equivalent to in "$@". The bash shell works the same way. – RobertL Oct 24 '15 at 23:34