[ILUG] Spaces in arguments in a bash for loop

Brady, Padraig Padraig.Brady at compaq.com
Fri Nov 3 13:38:55 GMT 2000


IFS is good if you want the shell to parse the
filenames. But if you want external commands
like grep to parse the names xargs -0 is what you want:
Note you probably want -r also, which means don't 
run the command if no input. Of course you need commands
that output \0 between filenames. find has a -print0
option to do this, but this doesn't work if you want
to pipe the output from something that doesn't support
\0 as a delimiter, like grep in your case.
For this situation I find the following construct
using tr very useful:

grep ding fonts | tr '\n' '\0' | xargs -r0 grep -v TT

This is also useful for cases where you want to process
columns and the spaces in files messes things up. for e.g.
to sort files by size you could do:

find fonts -type f -printf "%p\0%s\n" |
tr ' \t\0' '\1\2 ' | 	#remove spaces, tabs in file names
sort +1nr +0 |    	#sort by filesize
tr '\1\2' ' \t'		#reset any space & tabs back

Note sort/uniq/sed/... have no problems with chars 1 & 2 etc.
Note sed breaks if you use \0 in it's input stream.

Padraig.

> -----Original Message-----
> From: Niall O Broin [mailto:niall at magicgoeshere.com]
> Sent: 03 November 2000 11:20
> To: ilug at linux.ie
> 
> While looking into my Dingbats fonts problem (q.v.) I 
> encountered another
> problem about which I've often meant to ask. An example may be best
> 
> niall at bagend:/tmp >grep ding fonts|grep -v TT
> -ttf-webdings-medium-r-normal-regular-0-0-0-0-p-0-iso8859-1
> -ttf-wingdings-medium-r-normal-regular-0-0-0-0-p-0-iso8859-1
> -ttf-zapfdingbats bt-medium-r-normal-regular-0-0-0-0-p-0-iso8859-1
> 
> 
> niall at bagend:/tmp >for dingfont in `grep ding fonts|grep -v TT`
> > do echo $dingfont
> > done
> -ttf-webdings-medium-r-normal-regular-0-0-0-0-p-0-iso8859-1
> -ttf-wingdings-medium-r-normal-regular-0-0-0-0-p-0-iso8859-1
> -ttf-zapfdingbats
> bt-medium-r-normal-regular-0-0-0-0-p-0-iso8859-1
> 
> 
> As you can see, in the second command, where I used the first 
> command's
> output in a substitution, I get four lines of output, although I
> only expect three. I know WHY this is happening (the space in 
> the third
> output line is being seen as a separator, hence dingfont gets 
> four different
> values rather than three) but I'd like to know how to stop it 
> happening. I
> regularly have to deal with files with embedded spaces in 
> their names, and
> some of what I need to do would be done nicely in a for loop 
> as above, but
> the embedded spaces screw things up for me. Is there a neat 
> way of solving
> this problem ? I say neat because one way which occurs to me is this
> 
> niall at bagend:/tmp >for x in `grep ding fonts|grep -v TT|sed 
> -e 's/ /*/g'`; do
> echo `echo $x|sed -e 's/*/ /g'`; done
> -ttf-webdings-medium-r-normal-regular-0-0-0-0-p-0-iso8859-1
> -ttf-wingdings-medium-r-normal-regular-0-0-0-0-p-0-iso8859-1
> -ttf-zapfdingbats bt-medium-r-normal-regular-0-0-0-0-p-0-iso8859-1
> 
> but that sucks large hairy rocks (though I must say that I 
> only just thought
> of it, and I'll use it in future unless one of you geniuses 
> can come up with
> the 'right' answer)
> 
> The bash man page is rather unhelpful. It says
> 
> Bash performs the expansion by executing command and 
> replacing the command
> substitution with the standard output of the command, with 
> any trailing
> newlines deleted. Embedded newlines are not deleted, but they 
> may be removed
> during word splitting.
> 
> As I see it, embedded newlines ARE deleted. Perhaps they are 
> "removed during
> word splitting" but what does that mean exactly ? When I do 
> 
> echo `grep ding fonts|grep -v TT` > xx
> 
> I can't see that I'm doing any word splitting, and yet the 
> resultant file xx
> only has one line.
> 
> BTW the result's the same whether I use ` substitution or the 
> new $() style.
> 
> Regards,
> 
> 
> Niall




More information about the ILUG mailing list