4

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?

1
  • You could also just use find /Applications -maxdepth 1. If you just want directories, use find /Applications -maxdepth 1 -type d.
    – Wildcard
    Sep 7, 2016 at 1:11

4 Answers 4

8

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.

3
  • :0 I'll choose the one that served me best
    – Jack
    Sep 6, 2016 at 21:36
  • @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/*
    – roaima
    Sep 6, 2016 at 21:59
  • And, depending on the dotglob setting, will or will not pick up "hidden" files
    – Jeff Schaller
    Sep 7, 2016 at 0:18
8

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
7
  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.
0
-4

This format allows you to choose from all the listing and sorting options of 'ls':

ls -at $DIR | while read i; do echo $i; done
2
  • 2
    Using $DIR without "s sourrouding it is bad. And the need to parse the ls output puts unnecessary restrictions as well.
    – glglgl
    Sep 7, 2016 at 7:31
  • Using $i without quoting it is bad, too. Sep 7, 2016 at 22:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.