Suppose I have made some non-conventional use of make. Suppose further that I've come up with a name scheme within this usage that is elegant and useful with tools other than make, and which is *almost* fitting perfectly into the make paradigm.

I can *almost* leverage make built-ins to accomplish this task, and am looking for a bit of magic to make it 'just work' within the semantics and grammar of the system.

Right now, I have a buildable process that depends as follows:

```
# "<-" = "depends on"
foo.bar.biz.baz.new <- foo.bar.biz.baz.extension bar.biz.baz.new
bar.biz.baz.new <- bar.biz.baz.extension biz.baz.new
biz.baz.new <- biz.baz.extension baz.new
baz.new <- baz.extension

# and the following rules should suffice, where $(magic ...) is a stand-in for what I'd like to do:]
SHELL:=/usr/bin/env bash 
.SECONDEXPANSION
%.new: $$*.extension $(magic $$*)
  ...

build: foo.bar.biz.baz.new

```

What I am looking for is some magic swapper that:

```
a...b  -> ...c if ... != ""

# so, it chops off the prefix (dot-delimited), a
# and swaps the suffix only if something is present other than the suffix

```

I think this could be:

```
$(filter-out .c, $(patsubst %,%.c $(not-prefix $$*)))

```

If *not-prefix* existed, and I am wondering whether there is some built-in that more or less accomplishes this task out of the box?

Alternatively, is there some really compact bashism that can accomplish this?

For example:

```
$(shell echo "$$*" | sed -E 's/[^.]*(.*)\.[^.]*$$/\1.new/' | grep -v -E '^\.new$$')

```

Is super windy and verbose, but maybe there is some compact way to do this?

---

The most readable I've come up with so far:

```
%.new: $$*.extension $(filter-out .new, $(shell echo "$$@" | cut -d '.' -f 1 --complement))

```

**Update** Minimal verifiable example of the tree-build recursion problem:

```
%.ext:
   @touch $@

 .SECONDEXPANSION:
 %.new: $$*.ext $(filter-out new, $(shell echo "$$@" | cut -d '.' -f 1 --complement))
   @echo "@: $@"
   @echo "<: $<"
   @echo "^: $^"
   @echo $(filter-out new, $(shell echo "$@" | cut -d '.' -f 1 --complement))

```

```
$ make descendant.ancestor.new

@: descendant.ancestor.new
<: descendant.ancestor.ext
^: descendant.ancestor.ext
ancestor.new
rm descendant.ancestor.ext

```

---

Next, I add in the second "$" sign to the rule, so that it executes during the second expansion instead:

```
%.ext:
   @touch $@

 .SECONDEXPANSION:
 %.new: $$*.ext $$(filter-out new, $$(shell echo "$$@" | cut -d '.' -f 1 --complement))
   @echo "@: $@"
   @echo "<: $<"
   @echo "^: $^"
   @echo $(filter-out new, $(shell echo "$@" | cut -d '.' -f 1 --complement))

```

Which yields:

```
$ make descendant.ancestor.new
make: *** No rule to make target 'descendant.ancestor.new'.  Stop.

```

---

Ultimately, I think this should be something like:

```
.SECONDEXPANSION:
 %.new: $$*.ext | $$(filter-out new, $$(shell echo "$$@" | cut -d '.' -f 1 --complement))

```

But instead what I have done to make it "just work" is:

```
%.ext:
   @touch $@

 .SECONDEXPANSION:
 %.new: $$*.ext .FORCE
   @echo "@: $@"
   @echo "<: $<"
   @echo "^: $^"
   @$(eval prior=$(filter-out new, $(shell echo "$@" | cut -d '.' -f 1 --complement)))
   @$(if $(prior),$(MAKE) $(prior))
   @echo "ta-da: idempotent, depth first tree recursion @:$@"

 .FORCE:

```

Which yields a more brittle behavior than the rule line:

```
$ make -s branch.root.new
@: branch.tree.new
<: branch.tree.ext
^: branch.tree.ext .FORCE
@: tree.new
<: tree.ext
^: tree.ext .FORCE
ta-da: idempotent, depth first tree recursion @:tree.new
ta-da: idempotent, depth first tree recursion @:branch.tree.new

```