Loop over everything in a directory?
Solution 1
-
As noted by Jeff Schaller,
*
normally works likels
— 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 optiondotglob
with the commandshopt -s dotglob
This will cause
*
to work likels -A
— it still won't show.
and..
themselves, but will show everything else beginning with.
. -
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 optionglobstar
with the commandshopt -s globstar
This will cause
**
as a filename component to mean everything here and below. Sofor 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, andfor file in /Applications/**/*.txt
will find all files whose names end with
.txt
. -
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
. - 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
Related videos on Youtube
Comments
-
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 almost 8 years:0 I'll choose the one that served me best
-
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 almost 8 yearsAnd, depending on the dotglob setting, will or will not pick up "hidden" files
-
glglgl almost 8 yearsUsing
$DIR
without"
s sourrouding it is bad. And the need to parse thels
output puts unnecessary restrictions as well. -
G-Man Says 'Reinstate Monica' almost 8 yearsUsing
$i
without quoting it is bad, too.