Loop over everything in a directory?

6,691

Solution 1

  1. As noted by Jeff Schaller, * normally works like ls — it will not show things whose names begin with . (a period).  If you are using bash, and you want to get things whose names begin with ., set (turn on) the shell option dotglob with the command

    shopt -s dotglob
    

    This will cause * to work like ls -A — it still won't show . and .. themselves, but will show everything else beginning with ..

  2. Your question mentions "everything in a directory".  This is a somewhat ambiguous phrase.  If you mean everything in the (top-level) /Applications directory, then the other answers are fine.  But if you want everything in the /Applications tree (i.e., everything in the /Applications directory and its subdirectories), and you're using bash, set the shell option globstar with the command

    shopt -s globstar
    

    This will cause ** as a filename component to mean everything here and below.  So

    for file in /Applications/**
    do
        echo "$file"
    done
    

    will list all objects (files, directories, etc.) in the /Applications tree.

    Note that this cannot be combined with other characters at the same component level; i.e., you can't do things like foo**bar.  However, you append other components after the **.  For example,

    for file in /Applications/**/README
    

    will loop through all files named README in the /Applications tree, and

    for file in /Applications/**/*.txt
    

    will find all files whose names end with .txt.

  3. You can set multiple options at once; e.g., with

    shopt -s dotglob globstar
    

    See the bash documentation for a complete list of options.  You can unset options with shopt -u.

  4. You should always quote all your shell variable references (e.g., "$file") unless you have a good reason not to, and you're sure you know what you're doing.

Solution 2

The * is called a shell globbing (pathname expansion) operator (? and [] too), when you call it unquoted, it will expand to all the files in the current directory (without any directory prefix). If you use a prefix e.g. /foo/*, it will be expanded to all files in directory /foo.

Note that, it is used to match certain files too, for example to match only the files that start with foo and ends in bar in the current directory, use the glob pattern:

foo*bar

So, the for loop can now takes the form:

for f in foo*bar; do echo "$f"; done

Read the man page of your shell to get more idea on shell globbing.

Solution 3

To iterate over the files (and subdirectories) in a directory, you can use

for file in /Applications/*
do
    echo "$file"
done

Note that if no match is found, the file variable will contain the /Applications/* string literally (with the asterisk), and this may cause errors if the following commands expect an existing path. If you want to do nothing if no file is matched, you can use the nullglob option:

shopt -s nullglob
for file in /Applications/*
do
    echo "$file"
done
Share:
6,691

Related videos on Youtube

Jack
Author by

Jack

I love programming, video games, and reading.

Updated on September 18, 2022

Comments

  • Jack
    Jack almost 2 years

    Alright, before this is immediately closed as a duplicate, let me explain. I have attempted many methods such as:

    for d in /Applications ; do
       echo "$d"
    done
    

    but that returns

    /Applications

    instead of the contents of /Applications.

    I also tried:

    #!/bin/bash
    FILES=/Applications
    
    for file in $FILES
    do
       echo $file
    done
    

    Which is basically the same thing. I noticed, though, that when I just do:

    #!/bin/bash
    
    for file in *
    do
        echo $file
    done
    

    It correctly echoes all of the folders in my home folder. Anyone know what's going on?

  • Jack
    Jack almost 8 years
    :0 I'll choose the one that served me best
  • roaima
    roaima almost 8 years
    @Jack be aware that the * wildcard doesn't differentiate files, folders, or any other entity that can be found in a directory. So if you have a directory inside your /Applications it will also get matched by /Applications/*
  • Jeff Schaller
    Jeff Schaller almost 8 years
    And, depending on the dotglob setting, will or will not pick up "hidden" files
  • glglgl
    glglgl almost 8 years
    Using $DIR without "s sourrouding it is bad. And the need to parse the ls output puts unnecessary restrictions as well.
  • G-Man Says 'Reinstate Monica'
    G-Man Says 'Reinstate Monica' almost 8 years
    Using $i without quoting it is bad, too.