3

In a simple cycle like the following

for f in $(ls -1) ;
        do
        something
done

I would like to store each line of the output of ls -1 in the variable f.

Is there a way to do this without setting IFS=$'\n'?

8
  • 8
    Don't parse ls!
    – devnull
    Apr 27 '14 at 13:13
  • Within the loop, you can access each line of output using the variable f.
    – devnull
    Apr 27 '14 at 13:14
  • Moreover, there are far too many questions that iterate over the results of find, even ls. Seems that you want to store the result into an array, though.
    – devnull
    Apr 27 '14 at 13:15
  • 2
    You could use find instead. Search for find, -print0.
    – devnull
    Apr 27 '14 at 13:24
  • 4
    He means don't parse ls precisely because that causes the type of problem you are facing.
    – terdon
    Apr 27 '14 at 13:34
14

As we said in the comments, don't parse ls it is prone to errors and completely unnecessary anyway. All you need is

for f in *;
do
        something
done

That will iterate through the files and directories1 in your current directory and save each of them (spaces and all) as $f. For example:

$ ls -A1
file1
file 2
$ for f in *; do echo "File is '$f'"; done
File is 'file1'
File is 'file 2'

1 In bash, this will ignore files/directory names starting with . (hidden files) unless you have set dotglob with shopt -s dotglob.

3
  • You can do ls -q - but I like your shell glob better. Personally I prefer ( set -- * ) because then I get them all at the same time addressable as $1 $2 $3... or in the shell $@ array. The end result is the same though - because I'll inevitably use a while or until loop anyway.
    – mikeserv
    Apr 27 '14 at 14:00
  • 2
    @mikeserv -q does not help at all, it just replaces control characters with ? so yes, a \n will be shown as ? but that will just break the script (since you can't actually use the file since its name does not contain a literal ?) and in any case, the -q will still fail on file names with spaces.
    – terdon
    Apr 27 '14 at 14:05
  • Well, if you've got that much you can get the file name by simply expanding the variable. And it doesn't fail if $IFS is handled correctly. That's why they use ? - its a shell glob for any character. In any case, this will portably handle setting all positionals to .dot or not files: for glob in ".[!.]*" "[!.]*" ; do set -- $glob "$@" && [ -e "./$1" ] || shift ; done
    – mikeserv
    Apr 27 '14 at 14:08
0

Use while loop instead:

$ touch "one file"
$ touch "second  file   edsfs"
$ ls
one file  second  file   edsfs
$ ls -1
one file
second  file   edsfs
$ for f in $(ls -1); do echo "\"$f\""; done
"one"
"file"
"second"
"file"
"edsfs"
$ while read f; do echo "\"$f\""; done < <(ls -1)
"one file"
"second  file   edsfs"
1
  • 1
    Yes, the while loop helps deal with spaces. It does not, however, help deal with filenames with newlines or, backslashes. Really, just don't parse ls. Ever.
    – terdon
    Apr 27 '14 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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