LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   change for-loop delimiter character? (https://www.linuxquestions.org/questions/programming-9/change-for-loop-delimiter-character-521128/)

galle 01-20-2007 07:10 AM

change for-loop delimiter character?
 
Hello,

I'm not sure if the subject is 100% correct, but it was the best I could come up with. I wanted to make a simple for loop to apply many files to one command:
Code:

for i in `ls *eps`; do epstopdf $i; done
However this method fails when the filenames contain spaces. I tried using sed to insert \ before the spaces and surrounding the filenames in quotes, but it seems the for-loop ignores all of this and splits the arguments at the spaces no matter what. Does anyone know how to only split the input e.g. at newlines?

And yes, I know I could just replace the space with underscore and; voilą! I want to know if this can be done though :)

pwc101 01-20-2007 07:21 AM

try:
Code:

for i in `ls *eps`; do epstopdf "$i"; done
second thoughts:
Code:

for i in *eps; do epstopdf "$i"; done

galle 01-20-2007 07:45 AM

Great! The last one worked perfectly. I don't understand why though :) How does '*eps' differ from 'ls -c1 *eps'?

And the quotes in the 'do' part of the loop doesn't seem to make any difference since the filenames are split up in the first part of the loop. Is there no way to explicitly tell it to ignore a space?

pwc101 01-20-2007 07:55 AM

I don't really know to be honest, but I suspect it's got something to do with shell expansion of *. That is to say, the shell (bash?) handles the *eps part, and for each iteration of the loop, it moves to the next file, whereas if you use `ls -c1 *eps`, all the eps files in your directory get passed to the for loop as a long line of files since the ls is expanding the *, rather than bash. When it's been expanded by ls, epstopdf can't handle that sort of input (a long list of many files).

If you're interested, there's someone on these forums called matthewg42 who explained this really well in another thread somewhere. I'll have a look to see if I can find it.

galle 01-20-2007 08:31 AM

Did you mean this:
Quote:

Originally Posted by matthewg42
So whet you do
Code:

ls *.dta
...the shell expands the list fist and passes the list to ls. ls never sees the meta-character, *. I only mention it because for a lot of DOS veterans like myself, this was the other way round. It's a moment of epiphany for a lot of people to realise how it's working. Was for me at any rate :)

This came as a surprise to me, I must admit... But now I see what you where talking about a lot better :)

pwc101 01-20-2007 08:48 AM

This is what the bash manpage has to say on *:
Code:

Special Parameters
      The  shell  treats  several parameters specially.  These parameters may
      only be referenced; assignment to them is not allowed.
      *      Expands to the positional parameters, starting from  one.  When
              the  expansion occurs within double quotes, it expands to a sin-
              gle word with the value of each parameter separated by the first
              character of the IFS special variable.  That is, "$*" is equiva-
              lent to "$1c$2c...", where c is the first character of the value
              of  the IFS variable.  If IFS is unset, the parameters are sepa-
              rated by spaces.  If IFS is  null,  the  parameters  are  joined
              without intervening separators.

and on IFS
Code:

IFS    The Internal Field Separator that is  used  for  word  splitting
              after  expansion  and  to  split  lines into words with the read
              builtin  command.  The  default  value  is  '<space><tab><new-
              line>'.

If you're interested in understanding this more than me (!), have a look for globbing and regular expressions. I think that these are all the different ways of expanding various variables :)

ascending_8 08-19-2009 10:15 AM

I seem to have a similar problem with the following which searches for all the files not accessed for a year:

for i in `find ./ -name "*" -atime +365`; do ls -lh ${i}; done

I get what I expect until I find files with spaces in their names.

NOTE: I don't actually want to ls the resulting finds, this is just for demonstration of the problem and minimising the code here.

I attempted using sed to replace ' ' with '\ '
and awk to place double quotes around the names.

After reading this thread it seems I need to set the "IFS" with end of line \n ?

IFS='\n'
seems not to work so a little more googling brought me to:
IFS=$'\n'

eg
IFS=$'\n';for i in `find /home/keith/ -name "*" -atime +365`; do ls -lh ${i}; done


All times are GMT -5. The time now is 01:53 PM.