0

If I want to loop over a statically assigned directory I can do:

cd /path/to/directory
for file in *
do
    echo 'Found file' $file
done

If I wanted to pass the directory as an argument, then I could:

cd $1
for file in *
do
    echo 'Found file' $file
done

If I move the $1 argument into the loop, I get an error, because it's not an array:

for file in $1
do
    echo 'Found file' $file
done

Is there a better way to do this without having to cd into the directory first?

2 Answers 2

4

If I understand right, you're trying to loop over the files in the directory specified by $1. In that case, you can do this:

for file in "$1"/*
do
    echo 'Found file' "$file"
done

Note that I've also enclosed all variable references in double-quotes. This is almost always a good idea, since it prevents misparsing if the variables contain spaces, tabs, wildcards, etc (all of which are legal in filenames). On the other hand, the * cannot be quoted, or it won't get expanded; so "$1"/* is half-quoted to get the right treatment.

Sign up to request clarification or add additional context in comments.

Comments

-1

@Gordon Davisson's answer should work. He's using what's called globbing to get the contents of whatever's in $1. Alternatively to the globbing, you could just use ls

for file in $(ls $1}); do
  echo "Found file ${file}"
done

You could use backtics:

for file in `ls $1`; do
  echo "Found file ${file}"
done

There's a lot of ways to make this work. If you want to only print things that are file (not subdirectories):

dir=$1
for file in $(ls $dir); do
  if [[ -f ${dir}/${file} ]]; then
    echo "File found ${file}"
  fi
do

Cheers!

5 Comments

This is subject to all the drawbacks of parsing ls.
Thanks for the link to that article. As far as I can tell, the issue comes when you have files with newlines in the names of the files. So, if that's the edge-case we're worried about here, I agree that parsing ls is not the right approach. Thankfully, I don't put newlines in my file names, so I've never had any issue using the output of ls in a for loop.
@JawguyChooser Using $( ) to get the output of ls will cause trouble with filenames that contain not just newlines, but spaces, tabs, and shell wildcards as well. (I use macOS, so spaces are common in filenames.) There are ways to work around some of these, but not all (and it's more work than it's worth). Using wildcards directly is simpler and more reliable.
@GordonDavisson Fair enough. I suppose I'm in the class of people who doesn't use special characters in files names, so I've never run into the troubles you describe. (BTW, isn't the workaround just to quote the subshell?: for file in "$(ls)"; do). Nevertheless, I consider myself corrected. When living in a world of people who put things like spaces, tabs and special characters in filenames (really?!), parsing the output of ls may be problematic.
for file in "$(ls)" will treat the output of ls as a single string, so it's not a solution. People will always do weird things that break stuff, and getting into the habit of writing scripts in a way less prone to breaking is a good idea, even if your solution would work for you, the way you use things. As soon as other people use your scripts, they'll do things you wouldn't.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.