Mawnster
Mawnster

Reputation: 673

linux iterate over files in directory

I'm trying to iterate over each file in a directory. Here's my code so far.

while read inputline
do
  input="$inputline"
  echo "you entered $input";

if [ -d "${input}" ]
  then
    echo "Good Job, it's a directory!"

    for d in $input
      do
        echo "This is $d in directory."
      done
   exit

my output is always just one line

this is $input directory.

why isn't this code working? what am I doing wrong?

Cool. When I echo it prints out

$input/file

Why does it do that? Shouldn't it just print out the file without the directory prefix?

Upvotes: 5

Views: 8055

Answers (3)

John Henckel
John Henckel

Reputation: 11357

You would think that looping over files would be easy, right? But this is full of pitfalls in bash.

Using globs is the WORST. Trust me, don't do it

for x in *; do          # <--- bad for many reasons
    echo the file name is $x
done

Using find is better, for instance.

for x in `find . -maxdepth 1 -type f`; do  # <-- assume no filename has spaces
    echo the file name is $x
done

find has a lot of options to filter results by name, by date, by owner... whatever. It is very powerful.

However using a for-find FAILS if the filename contains spaces. To fix that use...

while read x; do
    echo the file name is $x
done < <(find . -maxdepth 1 -type f)

Or if you don't like that weird done syntax, instead you can use:

result=`find . -maxdepth 1 -type f`
while read x; do
    echo the file name is $x
done <<< $result

However, what if the filename contains a linefeed?! Can that happen? Yes it can happen, but it is extremely rare. So if you are PARANOID you can do:

while read -r -d '' x; do
    echo the file name is $x
done < <(find . -maxdepth 1 -type f -print0)

In my opinion the extra mess is not worth it, so I don't recommend it. People who put linefeeds in filenames deserve to feel pain.

Upvotes: -1

DigitalRoss
DigitalRoss

Reputation: 146073

If you want to simplify it somewhat and get rid of the directory check, you could just write it to work on files and directories, perhaps something like:

read inputline
ls "$inputline" | while read f; do
    echo Found "$f"
done

Upvotes: 2

pixelbeat
pixelbeat

Reputation: 31718

for d in "$input"/*

Upvotes: 7

Related Questions