16

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.

4 Answers 4

20
#!/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
3
  • 3
    Better to use if [ -f "$file" ]; then .... Not a directory would return not only regular files but sockets and symlinks too.
    – JRFerguson
    Mar 13, 2017 at 19:29
  • @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. Mar 13, 2017 at 20:41
  • 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. Mar 14, 2017 at 8:07
3

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.

2

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.

0

Bash for loop excluding sub-directories ('/') and links (@):

for f in `ls|egrep -v '/|@'`; do echo $f; done
0

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .