Kalcifer
Kalcifer

Reputation: 1620

Prepend a String to a Regex Match Using Bash

I have a file that has a certain string on some lines that takes the form of either [Name](./path_to_name_directory) or [Name](./path_to_name_directory/notes.md) each with some unimportant list items. For the lines that do not have notes.md at the end of the file path within the parenthesis, Name gets prepended to that line.

To try and solve this, I originally had the following command

sed 's/\[(.*)\]\(\.\/.*\/(?!notes\.md)/\1&/g' ./file.md

but I eventually found out that sed does not support lookaheads or lookbehinds, so I moved to using perl to try and accomplish the same. I thought it would be as simple as doing

perl -pe 's/\[(.*)\]\(\.\/.*\/(?!notes\.md)/\1&/g'

but it did not work, and I'm not entirely sure where to go from here.

EDIT 1:

Sample Input File:

- [Name 1](./path_to_name_1)
  - Unimportant list item.
- [Name 2](./path_to_name_2/notes.md)
  - Unimportant list item.

Sample Output File:

- Name 1 [Name 1](./path_to_name_1)
  - Unimportant list item.
- [Name 2](./path_to_name_2/notes.md)
  - Unimportant list item.

Upvotes: 3

Views: 513

Answers (3)

Carlos Pascual
Carlos Pascual

Reputation: 1126

With awk, you can set FS as [][]|/|). This way you can get the content of $2 and $5 and put the condition.

awk -v FS='[][]|/|)' '$2 ~ /^Name [[:digit:]]/ && $5 !~ /notes.md/ {sub(/^. /, "&"$2" " , $0)} 1' file
- Name 1 [Name 1](./path_to_name_1)
  - Unimportant list item.
- [Name 2](./path_to_name_2/notes.md)
  - Unimportant list item.

Upvotes: 1

Kalcifer
Kalcifer

Reputation: 1620

An option that I came up with using @ RavinderSingh13's answer and this related answer is the following

sed -E '/.*notes\.md.*/!s/\[(.*)\]/\1&/g'

/.*notes\.md.*/! tells sed to not match if the string matches that regex. In other words, sed will only match lines that do not match the address specification (See code block #5 of section 4.1 of the GNU Sed Manual).

s/\[(.*)\]/\1&/g tells sed to capture group the inner string of the square brackets and prepend it to the entire match; the portion of the regex that accomplishes the positional placement is \1&, where \1 is the capture group, and & references the entire matched portion of the string.)

Upvotes: 1

RavinderSingh13
RavinderSingh13

Reputation: 133518

With your shown samples, please try following.

awk '
!/notes\.md\)$/ && match($0,/\[Name [0-9]+/){
  $1=$1 OFS substr($0,RSTART+1,RLENGTH-1)
}
1
' Input_file

Explanation: Adding detailed explanation for above. This is only for explanation purposes.

awk '
##Starting awk program from here.
!/notes\.md\)$/ && match($0,/\[Name [0-9]+/){
##Checking condition if current does not end with notes.md) then match [Name digits in current line.
  $1=$1 OFS substr($0,RSTART+1,RLENGTH-1)
##Re-create 1st field which has current $1 OFS and sub string of matched regex value.
}
1
##This will print current edited/non-edited line here.
' Input_file ##Mentioning Input_file name here.

Upvotes: 3

Related Questions