3

I need to get all paths which has a specific file:

find apps  -type f -name "project.json"

This returns something like

apps/sub/frontend-e2e/project.json
apps/sub/frontend/project.json
apps/sub/backend/project.json

But I want to exclude all paths with -e2e in the last folder.

I tried something like

find apps  -type f -name "project.json" -not \( -path "*-e2e" -prune \)

Also I need to remove apps/ and /project.json from the beginning and the end of each path. So the result should be:

sub/frontend
sub/backend

In JS I would do

glob.sync('apps/**/project.json', {
    ignore: ['apps/**/*-e2e/project.json']
}).map((path) => {
    // do replacements
})
Cyrus
  • 84,225
  • 14
  • 89
  • 153
user3142695
  • 15,844
  • 47
  • 176
  • 332

2 Answers2

3

Like this:

$ tree apps/
apps/
└── sub
    ├── backend
    │   └── project.json
    ├── frontend
    │   └── project.json
    └── frontend-e2e
        └── project.json

4 directories, 3 files

$ find ./apps -not -path '*-e2e/project.json' -name project.json -printf '%h\n'
apps/sub/frontend
apps/sub/backend
Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
1

If you've got Bash 4.3 (released in 2014) or later, try this Shellcheck-clean code:

shopt -s dotglob extglob globstar nullglob
for path in apps/**/!(*-e2e)/project.json; do
    p=${path#*/}
    printf '%s\n' "${p%/*}"
done
  • shopt -s ... enables some Bash settings that are required by the code:
    • dotglob enables globs to match files and directories that begin with .. find shows such files by default.
    • extglob enables "extended globbing" (including patterns like !(*-e2e)). See the extglob section in glob - Greg's Wiki.
    • globstar enables the use of ** to match paths recursively through directory trees. This option was introduced with Bash 4.0 but it is dangerous to use in versions before 4.3 because it follows symlinks.
    • nullglob makes globs expand to nothing when nothing matches (otherwise they expand to the glob pattern itself, which is almost never useful in programs).
  • See Removing part of a string (BashFAQ/100 (How do I do string manipulation in bash?)) for an explanation of ${path#*/} and ${p%/*}.
  • See the accepted, and excellent, answer to Why is printf better than echo? for an explanation of why I used printf instead of echo to print the outputs.

Note that this code will not output anything for the path apps/project.json. It's not clear what you would want to output in that case anyway.

pjh
  • 6,388
  • 2
  • 16
  • 17
  • I do get the error `shopt: globstar: invalid shell option name`, although the output result is correct... – user3142695 Feb 27 '23 at 19:16
  • It sounds like you've got Bash 3 (e.g. because you are on MacOS). The `**` is being treated the same as `*` and it works because all of the matches are two levels down. Run `echo "$BASH_VERSION"` to check exactly which version of Bash you've got. – pjh Feb 27 '23 at 19:44