cat dirs.txt | while read dir; do
ls -al "$dir"
done
When you use the backtick operator the output is split into tokens at each whitespace character. read
, on the other hand, will read one line at a time rather than one word at a time. So the solution, which looks kind of odd, is to pipe the file into the loop so it can be read line by line.
You need to quote "$dir"
in the ls
command so that the entire file name, whitespace and all, is treated as a single argument. If you don't do that ls
will see two file names, /var/tmp/old
and files.txt
.
I'm probably going to get awarded the Useless Use of Cat Award. You can simplify this even further by removing the cat
:
while read dir; do
ls -al "$dir"
done < dirs.txt
This works because the entire while
loop acts like one big command, so just like you can pipe cat
into it, you can also use file redirection.
Taking it even further...
Depending on how dirs.txt
is generated you may just be able to get rid of it entirely and do everything in one command. If it's just a temporary file you could eliminate it by piping the command generates dirs.txt
into the while
loop directly, skipping the temporary file. For instance, replace
find /var -name '*old*' > dirs.txt
while read dir; do
ls -al "$dir"
done < dirs.txt
with
find /var -name '*old*' | while read dir; do
ls -al "$dir"
done
Pretend find
is whatever command you're doing to generate the file list.
And actually, if you are in fact using find
you can probably do everything in one big find
command without any loops or anything! For example, the above code using find
and while
could be done with a single find
command like this:
find /var -name '*old*' -exec ls -al {} \;
find
is a really flexible command that can both search for files matching all kinds of complicated criteria, and pass those files as command-line arguments to other commands using the -exec
option. When you use -exec
the {}
gets replaced with each file name.