Bash script to replace matched substrings within larger substring

Viewed 69

I'm trying to write a bash script to replace the newline characters and *s from comments, but only if that comment contains a particular substring.

// file.txt
/**
 * Here is a multiline
 * comment that contains substring
 * rest of it
 */

/**
 * Here is a multiline
 * comment that does not contain subNOTstring
 * rest of it
 */

I would like the final result to be:

// file.txt
/** Here is a multiline comment that contains substring rest of it */

/**
 * Here is a multiline
 * comment that does not contain subNOTstring
 * rest of it
 */

I have a regex that matches multiline comments: \/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*\/ but can't figure out the second part, of only matching with the substring, and then replacing all the /n * with just

So to make sure my question is articulated correctly

  1. Make a match of a substring within a file. i.e. comment
  2. Make sure that match includes substring.
  3. Replace all substring within the first match with another string. i.e. n/ * with
1 Answers

If python is your option, would you please try:

#!/usr/bin/python

import re                                                       # use regex module

with open('file.txt') as f:                                     # open "file.txt" to read
    str = f.read()                                              # assign "str" to the lines of the file

for i in re.split(r'(/\*.*?\*/)', str, flags=re.DOTALL):        # split the file on the comment including the comment in the result
    if re.match(r'/\*.*substring', i, flags=re.DOTALL):         # if the comment includes the keyword "substring"
        i = re.sub(r'\n \* |\n (?=\*/)', ' ', i)                # then replace the newline and the asterisk with a whitespace
    print(i, end='')                                            # print the element without adding newline
  • re.split(r'(/\*.*?\*/)', str, flags=re.DOTALL) splits "str" on the comment including the comment in the splitted list.
  • The flags=re.DOTALL option makes a dot match with newline characters.
  • for i in .. syntax loops over the list assiging "i" to each element.
  • re.match(r'/\*.*substring', i, flags=re.DOTALL) matches the element which is a comment including the keyword "substring".
  • re.sub(r'\n \* |\n (?=\*/)', ' ', i) replaces a newline followed by the " * " in the next line with a whitespace.
  • \n (?=\*/) is a positive lookahead which matches a newline followed by " */". It will match the last line of the comment block leaving the "*/" as is.

[Edit]
If you want to embed the python script in bash, would you please try:

#!/bin/bash

infile="file.txt"                       # modify according to your actual filename
tmpfile=$(mktemp /tmp/temp.XXXXXX)      # temporary file to output

# start of python script
python3 -c "
import re, sys

filename = sys.argv[1]
with open(filename) as f:
    str = f.read()

for i in re.split(r'(/\*.*?\*/)', str, flags=re.DOTALL):
    if re.match(r'/\*.*substring', i, flags=re.DOTALL):
        i = re.sub(r'\n \* |\n (?=\*/)', ' ', i)
    print(i, end='')
" "$infile" > "$tmpfile"
# end of python script

mv -f -- "$infile" "$infile".bak        # backup the original file
mv -f -- "$tmpfile" "$infile"           # replace the input file with the output
Related