2

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.
Inian
  • 80,270
  • 14
  • 142
  • 161
Kalcifer
  • 1,211
  • 12
  • 18
  • 5
    Please provide a sample input file and desired output. – Shawn Apr 04 '21 at 05:50
  • https://stackoverflow.com/questions/9053100/sed-regex-and-substring-negation check out this answer as a workaround: you can use a sed rule to match lines that end with "notes.md" and do nothing, plus a rule that matches what remains and does something. – Tordek Apr 04 '21 at 06:00
  • @Shawn , apologies. I added sample input and sample output in the edit. – Kalcifer Apr 04 '21 at 06:02
  • @Kalcifer, I would request you to add your code(which you have come up) in your answer, yes questioners could answer as well to their question. By doing this you are keeping your question clear(you could edit your question and make it like how it was asked to avoid confusions; since there is an answer section available for that), thank you. – RavinderSingh13 Apr 04 '21 at 06:52

3 Answers3

3

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.
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
1

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.)

Kalcifer
  • 1,211
  • 12
  • 18
1

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.
Carlos Pascual
  • 1,106
  • 1
  • 5
  • 8