Inspired by this rule by prwhite on GitHub
help:
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'`
I'm trying to make a version that replaces target files with spaces. I want to replace a part of a string with all spaces.
With the file input.txt
:
spec: $(ALL_FILES) ## Runs all specs
myst-spec: $(ALL_FILES) ## Runs just the in-language specs
build: $(SOURCE_FILES) ## Builds myst into an executable
check: $(ALL_FILES) ## Runs all crystal specs
clean: ## Cleans (deletes) docs and executables
help: ## Show this help.
This is the expected output:
spec: ## Runs all specs
myst-spec: ## Runs just the in-language specs
build: ## Builds myst into an executable
check: ## Runs all crystal specs
clean: ## Cleans (deletes) docs and executables
help: ## Show this help.
This is the rule i currently have:
help:
@fgrep -h "##" input.txt | fgrep -v fgrep | \
perl -pe 's/(.*):(.*)##(.*)/("$1:" . (" " x length($2)) . " $3")/e'
Note that fgrep
is used here, because actually this is supposed to be run on the makefile itself, but i use input.txt
here so you don't have to deal with the whole makefile.
Unexpectedly, i get this output:
:
:
:
:
:
:
What confuses me the most is that if i run the perl script directly on input.txt
(like this: cat input.txt | perl -pe 's/(.*):(.*)##(.*)/("$1:" . (" " x length($2)) . " $3")/e'
) – i get the expected output. What is the reason it gives different output? I realize it (probably) has something to do with fgrep, but I don't see how it would make a difference, so here I am.
If you want to use $
in a recipe you have to escape it from make by doubling it to $$
.
help:
@fgrep -h "##" input.txt | fgrep -v fgrep | \
perl -pe 's/(.*):(.*)##(.*)/("$$1:" . (" " x length($$2)) . " $$3")/e'
The above can be simplified:
help:
@perl -ne'next if !/##/; s/(.*):(.*)##(.*)/ "$$1:".( " " x length($$2) )." $$3" /e; print'
Or (5.10+):
help:
@perl -ne'next if !/##/; s/:\K(.*)(?=##)/ " " x length($$1) /e; print'