3

I'm trying to make a bash script that deals with every file in a directory. All of those file names begin with a dot, so they're hidden. When I try to use a wildcard to grab everything in the directory, the wildcard isn't expanding.

My code that loops over it looks like this right now:

#!/bin/bash
shopt -s extglob

for i in "$(pwd)"/*; do
  echo "$i"
done

The output is just /Users/.../*. The wildcard doesn't expand.

This is different than some of the other threads because it deals with hidden files specifically. If I add a file like test to the directory, then it works. I get /Users/.../test.

I tried running this in the terminal by itself as well and got the same result. How do I get the wildcard to expand for hidden files?

6

I figured it out! Looking more closely at the documentation for shopt, there's an option called dotglob that can be used to include filenames that begin with a dot!

I added shopt -s dotglob to the beginning of my script and it works now. The output now lists every hidden file and directory (except ./ and ../).

My script now looks like this:

#!/bin/bash
shopt -s extglob
shopt -s dotglob

for i in "$(pwd)"/*; do
  echo "$i"
done
3
  • 2
    Also useful: shopt -s nullglob makes a globbing expression expand to nothing if it matches nothing; "$PWD" holds the same value printed by pwd, but echo "$PWD" lets you save a fork compared to echo "$(pwd)" - in Bash, command substitution is performed using a child process.
    – fra-san
    Aug 26 '20 at 22:11
  • 2
    @fra-san, $(pwd) (as opposed to $PWD) also doesn't work properly when the path to the current working directory ends in newline characters. Aug 27 '20 at 8:54
  • 2
    Note that extglob is not necessary here for the expansion of that glob. extglob would b e needed if you wanted to use the extended ksh88 operators like @(...), !(...), *(...)... Aug 27 '20 at 8:55
1

posix workaround without dotglob

#!/bin/sh

for i in "$PWD"/* "$PWD"/.*
  do
    [ "${i##*/}" = . ] || \
    [ "${i##*/}" = .. ] || \
    [ "${i##*/}" = \* ] || \
    [ "${i##*/}" = .\* ] && continue

    echo "$i"
done

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.