Treat capture groups with custom function before using them in the replace part

Viewed 36

I have some markdown files with broken relative links. I wish to fix them. For instance I have this (very short) example file:

Please refer to [this first ressource](wrong/path/to/file) and [this other ressource](non/existing/text).
You can also search on [this website](https://example.net).

Note that there can be multiple links on the same line, and that there are also external links, which should stay untouched.

On a first approach, if we forget about external links, and if the correct resources pointed by the relative links were only placed in a sub-folder, we could have this approach:

sed -i -E "s/(\[.*\])\(([^\)]*)\)/\1(subfolder\/\2)/g" document.md

which would turn my example document into this:

Please refer to [this first ressource](subfolder/wrong/path/to/file) and [this other ressource](subfolder/non/existing/text).
You can also search on [this website](subfolder/https://example.net).

But we have 2 problems here:

  • External links are messed up
  • Correct resources pointed by the links are not simply in some sub-folders. The correct path can be determined from the wrong one though, but we have to go through the entire folder in order to do that. This could be done quite easily in a bash script for instance.

So I need a way to apply a function to my capture group before sed takes it to determine the replacement string. Here, the capture flag I need to process is \2.

Any solution even without sed is acceptable.

Thanks.

1 Answers

Concerning your second bullet point,

Correct resources pointed by the links are not simply in some sub-folders. The correct path can be determined from the wrong one though, but we have to go through the entire folder in order to do that. This could be done quite easily in a bash script for instance.

you have not mentioned what this bash script should do. In the following I assume you have defined a correct_path function which does the job:

correct_path () { echo ${1//@(wrong|non\/existing)/correct}; } # this example assumes shopt -s extglob

With that function defined, you can run the following command, which

  • executes a sed command to change each address to $(correct_path address) and ecloses the result in double quotes to preserve the newlines, "$(…)";
  • evals the line made up of echo, ", the "$(…)" generated above, and another ".
eval echo '"'"$(< os sed -E 's/(\[[^]]*\])\(([^)]*)\)/\1($(correct_path \2))/g')"'"' > os

However eval is evil.

Related