Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This is a follow up to a question posted on SO.

I've written a script called except which should print all filenames / directories except the ones given like so.

$ ls
a b c d
$ rm $(except b d)
$ ls
b d

The script I've written so far looks like this

shopt -s extglob
shopt -s nullglob

old_ifs=$IFS
IFS='|'
matches="!($*)"
IFS=' '

printf '%s' $matches
IFS=$old_ifs

This works more or less but the main problem is that printf doesn't seem to respect IFS set to (blank).

It just prints them without a space between. If I instead use echo, it works (except for the added newline). But for compatibility reasons I want to use printf for this task. How can I achieve this? What am I doing wrong?

I also tried using the %q modifier which also didn't result in the desired output.

printf '%q' $matches
share|improve this question
    
What about leaving out IFS and use just printf '%s ' $matches? (I mean include a literal space in the format string.) –  manatwork Feb 12 '13 at 10:15
    
@manatwork While that would work I don't want the extra blank behind the last match (I know I'm nitpicking here). –  helpermethod Feb 12 '13 at 10:19
    
printf '%s' $something : will print the content of $something, with nothing around it. So it's just what you ask it to do... And use quotes (") to save and restore IFS, otherwise it won't be the exaxt content. ( OLDIFS="$IFS" ; .... ; IFS="$OLDIFS" ; ...) –  Olivier Dulac Feb 12 '13 at 10:57

1 Answer 1

up vote 2 down vote accepted
$ ls
a b c d
$ rm $(except b d)
$ ls
b d

That can't work, at least not reliably, because "except" cannot decide how the shell will split (and further expand) its output before passing it to the rm command.

To answer your question, printf doesn't use $IFS. The only command that uses IFS is read. Other than that, $IFS is used by the shell for word splitting and to join the positional arguments in "$*".

You probably want:

 printf '%s ' $matches

Or

 printf '%s\n' $matches

But again, in

 rm $(except a b)

The shell that interprets that command line will split the output of except according to its own $IFS (by default space, tab or newline, which is why using space or \n above makes no difference) and will also expand the wildcards in there.

So if the files other than a and b are "this file.txt" and **a**, except will output "this file.txt **a** " and you will end up trying to remove this, file.txt and a (since **a** will expand to all the files with a in their name).

If you want to join the matches with spaces without the trailing space, you could do:

IFS=
set -- $matches
IFS=' '
matches="$*"
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.