tags:

views:

112

answers:

3

I am batch converting some pictures with a quick and dirty bash script using ufraw :

IFS=$'\n'
PICS="/media/disk/kevin/Images/";
for pic in $(find $PICS -name "*CR2");
do
    ufraw-batch $pic --out-type jpg --size=2048 --overwrite --out-path=$PICS;
    rm -f $pic
done;
IFS=" ";

It's running fine with the usual rights, but if I run it with :

sudo ./convert.sh

I got this strange error :

find: "/media/disk/kevi" : no such file or directory.

I made it :

IFS=$'\n'
PICS="/media/disk/kevin/Images/";
echo PICS;

Then I got surprisingly :

/media/disk/kevi /Images/

WTF ?

+3  A: 

You're winding up with $IFS being "n"; it's not interpreting \n as a newline but as a meaninglessly escaped n. I vaguely suspect you're running into some sort of ill-documented protection of $IFS for root (since it's a well known exploit vector), but you might want to try embedding a literal newline instead of a symbolic one in your script using ctrl-v enter.

chaos
Thanks a lot chaos. Indeed, IFS seems protected for root and using a literal new line worked like a charm.
e-satis
Actually, this has nothing to do with root. Read the Shell Command Language description of Escape Character (http://www.opengroup.org/onlinepubs/009695399/).
Ned Deily
And that reference isn't helpful because it doesn't describe ANSI-C quoting ($'..') which you are using here. Sorry, my mistake.
Ned Deily
Hi chaos, I'm going to accept Ned Answer because he's explaining the "why". Thanks for helping me to solve that quickly anyway.
e-satis
A: 

Your code seems to have a typo. If the actual code is IFS='\n' or IFS="\n", you've set the separator to a list of two characters, \ and n. If IFS=\n, then one char A POSIX shell doesn't interpret \n as LF. It has nothing to do with root.

$ BLAH='\n'
$ echo $BLAH
\n
$ BLAH="\n"
$ echo $BLAH
\n
$ BLAH=\n
$ echo $BLAH
n
$ BLAH="Both\n\and\aregone"
$ echo $BLAH
Both   a d arego e
Ned Deily
As I wrote, this script run fine and the path display fine wihtout the admin right. If I strip the IFS replacement, the script doesn't work because IFS is a space and my loop ends up with working on toncated paths if they containes any space. BTW, this is not IFS='\n' but FS=$'\n'. This is very different.
e-satis
Sorry, I misunderstood the use of ANSI-C quoting in your example so this answer is irrelevant. See the more recent answer for a more likely explanation.
Ned Deily
+2  A: 

If you don't have an explict #! line in your script, chances are that the sudo-ed command is being run under /bin/sh rather than /bin/bash and, if you're running on a recent Linux system, chances are that /bin/sh is dash rather than bash. The maintainers of dash maintain that IFS is not supposed to interpret escape sequences (see, for instance, here).

$ more convert.sh
IFS=$'\n'
PICS="/media/disk/kevin/Images/";
echo $PICS;
ps
$ ./convert.sh
/media/disk/kevin/Images/
  PID TTY          TIME CMD
30827 pts/0    00:00:01 bash
32042 pts/0    00:00:00 bash
32043 pts/0    00:00:00 ps
$ sudo ./convert.sh
/media/disk/kevi /Images/
  PID TTY          TIME CMD
32044 pts/0    00:00:00 sh
32045 pts/0    00:00:00 ps
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 2009-08-06 19:10 /bin/sh -> dash

So the behavior you see is only indirectly related to running under root. You'd see the same if you explicitly used dash. And another way to work around the problem would be to include an explict #!/bin/bash in your script.

Ned Deily
Tested and indeed, that's seems like it. I switch the accepted answer, thank you for not only accepting your mistake but trying to contribute anyway after.
e-satis
Thanks! I found it hard to believe it that the issue was in sudo and I learned something new myself.
Ned Deily