Chage text in first bracket that are succeded by third/square brackets

Viewed 37

I want to append some text (.html) at the end of line in format [some_text](some/other/text); basically links in markdown syntax.

Example

[Test](test/link) would be [Test](test/link.html)
[Test](test/link1/link) would be [Test](test/link1/link.html)
[Test] would be [Test]
(test) would be (test)

So I was trying out unix sed with syntax: sed -i 's/\[*\](*)/.html)/g' filename.md. The said sed syntax is wrong and not working, can someone help? I'm open to using other tools like awk or perl, it is appropriate for this scenario.

Solution: sed -i 's/\(\[[^][]*]([^()]*\))/\1.html)/g' filename.md

Suggested by @WiktorStribiżew

2 Answers

Based on given samples:

$ cat ip.txt
[Test](test/link)
[Test](test/link1/link)
[Test]
(test)

# if closing ) should also be matched: sed -E 's/(\[[^]]+]\([^)]+)\)/\1.html)/'
$ sed -E 's/\[[^]]+]\([^)]+/&.html/' ip.txt
[Test](test/link.html)
[Test](test/link1/link.html)
[Test]
(test)
  • \[ match [
  • [^]]+ match one or more non ] characters
  • ]\( match ](
  • [^)]+ match one or more non ) characters
  • & backreferences entire matched portion
  • \1 backreferences portion matched by first capture group

With perl:

perl -pe 's/\[[^]]+]\([^)]+\K(?=\))/.html/'
  • \K helps to avoid capturing the text matched until that point
  • (?=\)) is a lookahead assertion to match ) character, this also is not part of the matched portion

Add -i option for either solutions once it is working as expected.

You can use

sed -i 's/\(\[[^][]*]([^()]*\))/\1.html)/g' filename.md

See the online demo.

The regex is a POSIX BRE expression that matches

  • \(\[[^][]*]([^()]*\) - Group 1:
    • \[ - a [ char
    • [^][]* - zero or more chars other than [ and ]
    • ] - a ] char
    • ( - a ( char
    • [^()]* - zero or more char sother than ( and )
  • ) - a ) char.

The -i option makes the replacements in the same file provided as input file in a GNU sed. g flag will look for all matches on the lines.

Related