mainThe GNU Bourne-Again SHell - Support: sr #110610, (unintended?) globstar symbolic...


sr #110610: (unintended?) globstar symbolic link behavior change in Bash 5

Submitter:  None
Submitted:  Tue 15 Feb 2022 02:43:28 AM UTC
Category:  None Priority:  5 - Normal
Severity:  2 - Minor Status:  Done
Privacy:  Public Assigned to:  None
Originator Email:  -email is unavailable- Open/Closed:  Open
Operating System:  Mac OS
* Mandatory Fields

Add a New Comment Rich Markup

Sun 20 Feb 2022 08:24:58 PM UTC, comment #4: 

Yes, a leading `**' is special-cased, for zsh compatibility. That was the only special-casing concession I made, so it matches everywhere else in a pattern. If you find other cases, please let me know.

Chet Ramey <chet>
Group administrator
Fri 18 Feb 2022 11:05:28 PM UTC, comment #3: 

Aha, thank you for that link!  That unravels the mystery.

So if I understand correctly, a leading `**` in a pattern will not match a symlinked directory itself, but a `.../**` elsewhere in the pattern (including `./**`) will match the symlinked directory itself.

I can definitely do the same in node-glob.

I guess this is "working as intended" then.

Isaac Z. Schlueter <isaacs>
Thu 17 Feb 2022 08:46:07 PM UTC, comment #2: 

The leading `**' thing was specifically pointed out as a bug/incompatibility with zsh (the only other implementation worth considering; the ksh93 one is too buggy).

zsh treats ./** the same as **; for me, that was a step too far.

Chet Ramey <chet>
Group administrator
Thu 17 Feb 2022 08:23:51 PM UTC, comment #1: 

Here's the discussion that prompted the change:

Chet Ramey <chet>
Group administrator
Tue 15 Feb 2022 02:43:28 AM UTC, original submission:  

Starting in Bash 4.3, globstar `**` patterns no longer walk indefinitely down recursive symbolic links.  This is very good!

However, I noticed a curious change in how this is implemented, which appears to start with (at least) Bash 5.1.


$ mkdir -p a/symlink/a/b; ln -s ../.. a/symlink/a/b/c

$ tree a
└── symlink/
    └── a/
        └── b/
            └── c -> ../../

4 directories, 0 files

$ ./bash -O globstar -O extglob -O nullglob -c 'for i in **/a/**/ ; do echo $i; done | sort | uniq'

$ ./bash -O globstar -O extglob -O nullglob -c 'for i in ./**/a/**/ ; do echo $i; done | sort | uniq'

$ ./bash --version
GNU bash, version 5.2.0(5)-alpha (aarch64-apple-darwin21.3.0)
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

A symbolic link points from `a/symlink/a/b/c` to `a/symlink`.  I would expect that the first `**` matches as far as `a/symlink/a/b/c`, but does not descend to child paths.  Then the `a` matches `a/symlink/a/b/c/a`.  The second globstar matches `.../b/c`, but does not descend further, as `c` is a symlink, resulting in `a/symlink/a/b/c/a/b/c` appearing in the results.

This is what happens if the pattern starts with a non-globstar portion, including `./`, as shown here.  This is also what happens when using `**/a/**/` in Bash 4.3.  However, in Bash 5, with a pattern starting with `**` not preceded by any other non-globstar pattern portion, it seems to not allow `**` to match any child paths of the symlink target, even if the `**` matches the symlink, and literal (existing) path portions follow it.

Placing a `./` in the pattern can show what the `**` is matching:

$ ./bash -O globstar -O extglob -O nullglob -c 'for i in **/./a/** ; do echo $i; done | sort | uniq'

$ ./bash -O globstar -O extglob -O nullglob -c 'for i in ./**/./a/** ; do echo $i; done | sort | uniq'

I maintain a glob implementation in JavaScript, which aims to match Bash's path expansion behavior exactly, so this threw a little bit of a curve ball at me.  If this is intended behavior, it would be good to know the specific conditions where `**` will not match a against symlink (even when child paths are specified literally).  If it is unintended behavior, then I can continue to model Bash 4.3 expansion behavior, and just include it as a caveat in my docs.

Thank you for all your work on Bash over the years.  It's such a lovely shell, and I still enjoy it every day.



(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:

No files currently attached


Depends on the following items: None found

Items that depend on this one: None found


Carbon-Copy List
  • -email is unavailable- added by isaacs (Posted a comment)
  • -email is unavailable- added by chet (Posted a comment)
  • -email is unavailable- added by None (Submitted the item)

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.


    Follow 2 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2022-02-20 chet StatusIn Progress Done
    2022-02-17 chet StatusNone In Progress

    Back to the top

    Powered by Savane 3.13-d3ae.
    Corresponding source code