Loop through files excluding directories

21,523

Solution 1

#!/bin/bash -

for file in "$dir"/*
do
  if [ ! -d "$file" ]; then
      "$@" "$file"
  fi
done

Note that it also excludes files that are of type symlink and where the symlink resolves to a file of type directory (which is probably what you want).

Alternative (from comments), check only for files:

for file in "$dir"/*
do
  if [ -f "$file" ]; then
      "$@" "$file"
  fi
done

Solution 2

Here's an alternative to using a for loop if what you need to do is simple (and doesn't involve setting variables in the main shell &c).

You can use find with -exec and use -maxdepth 1 to avoid recursing into the subdirectory.

[ -n "$1" ] && find "$dir" -type f -mindepth 1 -maxdepth 1 -exec "$@" "{}" \;

The [ -n "$1" ] is there to avoid executing all the files in the directory when the script isn't passed any arguments.

Solution 3

In zsh, you can use glob qualifiers to restrict wildcard matches by file type. For example, adding (.) after the pattern restricts it to regular files.

wc -w *(.)

To cope with file names beginning with - or ., use wc -c -- *(.N) or wc -c ./*(.N). If you want to include symbolic links to regular files as well, make that *(-.).

The other common shells have no such feature, so you need to use some different mechanism for filtering by file such as testing file types in a loop or find.

Share:
21,523

Related videos on Youtube

Tõnis Piip
Author by

Tõnis Piip

Updated on September 18, 2022

Comments

  • Tõnis Piip
    Tõnis Piip almost 2 years

    I need my script to do something to every file in the current directory excluding any sub-directories.

    For example, in the current path, there are 5 files, but 1 of them is a folder (a sub-directory). My script should activate a command given as arguments when running said script. I.e. "bash script wc -w" should give the word count of each file in the current directory, but not any of the folders, so that the output never has any of the "/sub/dir: Is a directory" lines.

    My current script:

    #!/bin/bash
    dir=`pwd`
    for file in $dir/*
    do
        $* $file
    done
    

    I just need to exclude directories for the loop, but I don`t know how.

  • laktak
    laktak over 7 years
    @roaima good idea!
  • JRFerguson
    JRFerguson over 7 years
    Better to use if [ -f "$file" ]; then .... Not a directory would return not only regular files but sockets and symlinks too.
  • roaima
    roaima over 7 years
    @JRFerguson based on the OP's question I would say that including sockets and pipes would be a really bad idea. As for symlinks, those are implicitly included with ! -d already.
  • Tõnis Piip
    Tõnis Piip over 7 years
    I used [ -f $file ] in my final script. Note the lack of quotation marks in the if condition. Almost everywhere I looked had quotation marks around $file, yet I had to delete them in order for my script to work.