Need to process files in current directory one at a time. I am looking for a way to take the output of ls
or find
and store the resulting value as elements of an array. This way I can manipulate the array elements as needed.
-
@ SiegeX How do I accept the answers? I have responded and thanked those who replied the best and upvoted them when I got privilege. What more can I do? – fzkl Jan 14 '11 at 11:01
4 Answers
To answer your exact question, use the following:
arr=( $(find /path/to/toplevel/dir -type f) )
Example
$ find . -type f
./test1.txt
./test2.txt
./test3.txt
$ arr=( $(find . -type f) )
$ echo ${#arr[@]}
3
$ echo ${arr[@]}
./test1.txt ./test2.txt ./test3.txt
$ echo ${arr[0]}
./test1.txt
However, if you just want to process files one at a time, you can either use find
's -exec
option if the script is somewhat simple, or you can do a loop over what find returns like so:
while IFS= read -r -d $'\0' file; do
# stuff with "$file" here
done < <(find /path/to/toplevel/dir -type f -print0)

- 135,741
- 24
- 144
- 154
-
2@ChandanChoudhury `read -r -d $'\0'` tells the `read` command to not treat backslash's as a special escape character and to delimit each word with the NUL character since we told `find` to use that as a delimiter with `-print0`. The `IFS=` part essentially unsets the special Internal Field Separator environment variable so it will not perform word splitting on tabs or spaces or new lines. The TLDR version is that these commands make it so that you can iterate over any filename no matther what kind of characters it contains. – SiegeX Nov 29 '14 at 22:55
-
Would it work to move the `IFS=` in front of the while : `IFS = ; while ... `? – Apr 28 '16 at 05:52
-
Also, is there a difference between this control structure and using a pipe: `find ... | while ....` ? – Apr 28 '16 at 05:55
for i in `ls`; do echo $i; done;
can't get simpler than that!
edit: hmm - as per Dennis Williamson's comment, it seems you can!
edit 2: although the OP specifically asks how to parse the output of ls
, I just wanted to point out that, as the commentators below have said, the correct answer is "you don't". Use for i in *
or similar instead.

- 15,344
- 5
- 45
- 67
-
3
-
6[Don't parse ls!](http://mywiki.wooledge.org/ParsingLs) `for i in *; do ...` does the same thing except that it isn't confused by funny characters in filenames, and runs faster (because it doesn't spawn another process). – Gordon Davisson Jan 13 '11 at 15:44
-
2@DennisWilliamson Is there any way to use a variable (containing the path) instead of `*`: `for in in $path/*` – PHP Learner Aug 25 '15 at 06:02
-
@PHPLearner: Yes. Just as you posted, but you should quote the variable. `for f in "$path"/*` – Dennis Williamson Aug 25 '15 at 12:05
-
@GordonDavisson `for i in *; do echo "$i" done` will output `*` *in empty* directory. – Alois Mahdal Jun 15 '17 at 16:15
-
@AloisMahdal Yes; shell glob expansion leaves the glob alone if there are no matching files (with `*`, that means "if there are no files"). In many cases this leads to a "file not found" type error, which if what you want. But if it's a problem in your script, either use `shopt -s nullglob` before it (and `shopt -u nullglob` after to avoid problems later on), or in a loop you can add `if [[ ! -e "$i" ]]; then continue; fi` at the beginning of the loop, so it'll skip nonexistent files. – Gordon Davisson Jun 15 '17 at 17:47
You actually don't need to use ls/find for files in current directory.
Just use a for loop:
for files in *; do
if [ -f "$files" ]; then
# do something
fi
done
And if you want to process hidden files too, you can set the relative option:
shopt -s dotglob
This last command works in bash only.

- 4,455
- 1
- 23
- 20
-
`%files` should be `$files`. Also, if you have Bash 4.X you can set `shopt -s globstar` and use `for files in **; do` to be recursive; fully removing the use for `find` – SiegeX Jan 13 '11 at 17:03
-
Thanks! I have corrected the error; by the way, I have Bash 4, but the OP (or other readers as well) may not have it :) – marco Jan 13 '11 at 17:29
Depending on what you want to do, you could use xargs:
ls directory | xargs cp -v dir2
For example. xargs will act on each item returned.

- 4,583
- 2
- 22
- 25
-
@Fritschy: If your `cp` supports it you can use `xargs cp -v --target-drectory dir2`. – Dennis Williamson Jan 13 '11 at 15:34
-
-
@Fritschy: One source of failure would be if any filenames contain spaces. Using `find ... -print0 | xargs -0` would fix that. How exactly is it messing up? It works for me. – Dennis Williamson Jan 13 '11 at 15:45