7

Disclaimer: I have just ported myself from Microsoft windows to Linux and my knowledge is mainly from different Linux forums.

I tried to use "**/*" command to provide a list of files to my mp3 player as below.

mpg123 **/*.mp3

Above commands works well but ignores the files of the current directory that is it brings the files from sub directories but not from current directory.

I tried same thing on ls command as well but with same result (of ignoring current directory files).

ls **/*

Is there any variation so that I could include current directory files as well.

Note: I got this command from this post on Stack Overflow but could not ask the author due to less reputation.

2
  • 4
    This is probably because the relevant shell option (globstar) is not enable in your interactive shell - what is the output of command shopt globstar? Commented Oct 26, 2020 at 14:12
  • 1
    If you want files from current directory and subdirectories which are only one level below the current directory, you can use simply ls *.mp3 */*.mp3.
    – FedKad
    Commented Oct 26, 2020 at 15:13

1 Answer 1

8

As steeldriver says, you need to enable the globstar shell option if you want Bash to treat ** recursively. It is turned off by default. That is, by default in Bash, ** behaves the same as *, and that is the behavior you are seeing.

  • shopt globstar tells you whether it is on or off.
  • shopt -s globstar turns it on (-s for "set").
  • shopt -u globstar turns it off (-u for "unset").

help shopt gives details on the shopt builtin.

The Bash reference manual explains * and **:

*

Matches any string, including the null string. When the globstar shell option is enabled, and ‘*’ is used in a filename expansion context, two adjacent ‘*’s used as a single pattern will match all files and zero or more directories and subdirectories. If followed by a ‘/’, two adjacent ‘*’s will match only directories and subdirectories.

With globstar, ** matches zero or more directories, which allows **/*.mp3 to match *.mp3 files in the current directory, as well as in subdirectories of the current directory, in subdirectories of those directories, and so forth. This is to say that **/*.mp3 matches the same files as if you wrote:

*.mp3 */*.mp3 */*/*.mp3 */*/*/*.mp3 ...

(where, in place of ..., the sequence continues on as deep as is needed for the directory tree being recursed; see also FedonKadifeli's comment, which presents the first two terms).

Without globstar, ** just has the same effect as *. Then **/*.mp3 is equivalent to */*.mp3, i.e., it matches *.mp3 files in subdirectories of the current directory, but not in subdirectories, nor in any deeper descendants of those subdirectories, nor in the current directory itself.

Note that, by default, globstar does not recurse into hidden directories--those whose names start with a .. * (and ?) does not match a . at the beginning of a path component; likewise, ** does not match a . at the beginning of any of the path components it would expand to. To change this (which changes it for both * and **), you can turn on the dotglob shell option. But you most likely don't want that.


Changes to shell options apply to a single running instance of the shell, as long as that instance is running (or until you change the option again). So turning globstar on in one Bash shell doesn't affect it in future Bash shells, nor in other Bash shells running at the same time.

However, if you want the change to last even shorter than that, you can use parentheses to make a subshell in which you set it and run your command:

(shopt -s globstar; mpg123 **/*.mp3)

Or maybe you do want globstar enabled in all your interactive Bash shells from now on. If so, you can put shopt -s globstar, on its own line, at the end of your ~/.bashrc file.

0

You must log in to answer this question.

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