0

Working in bash. I have a file.txt with contents in the following format.

default=60.0,
default=False,
default=(0.2, 0.2, 0.3, 1.0),
default="blend",
default="/path/to/directory")

There is other info on each line before and after what i am showing but this is the part i want to edit. i am trying to replace the values following the equals sign and before the comma with values stored in a variable. i can make it work if i know all the info of line number, what to replace, and what replacing with beforehand but as soon as i start working with variables it all falls apart. i can use sed -i '4s/default="blend",/default="burn",/' file.txt to replace blend with burn on line 4 but how can i do this with variables? i cant seem to find the right way to quote this. and obviously the data i am trying to replace is not consistent, some numbers, some strings, some quoted, some not, some bracketed, some not, some followed by ,, some followed by ). focused on line 4 currently, if var1=4 and var2="burn" and default= could be any of "blend, burn, or bump". so say i want to replace whatever follows default= with "burn" on line 4, var1=4 var2="burn"

Desired output:

default=60.0,
default=False,
default=(0.2, 0.2, 0.3, 1.0),
default="burn",
default="/path/to/directory")

hopefully what i am trying to accomplish makes sense because i'm stuck. how can i make this work? doesn't have to use sed if there is another simple way.

edit: contents of entire line are: parse.add_argument("-j", "--blend_type", default="blend", choices=["blend", "burn", "bump"], help="type of blend the shader can do")

using: sed -r "$var1{s/(default=\")(.*)(\".*$)/\1$var2\3/p}" file.txt

my output is parse.add_argument("-j", "--blend_type", default="burn")

and i want it to be parse.add_argument("-j", "--blend_type", default="burn", choices=["blend", "burn", "bump"], help="type of blend the shader can do")

i'm close but can't seem to keep the end of the line intact.

Skydivr
  • 1
  • 1
  • Please add your desired output (no description) for that sample input to your question (no comment). – Cyrus Feb 01 '21 at 16:59
  • please update the sample inputs with some sample before/after data on each line, in particular ... what's the delimiter between the `before`, `default=...` and `after` sections? – markp-fuso Feb 01 '21 at 17:14

3 Answers3

1

i can use sed -i '4s/default="blend",/default="burn",/' file.txt to replace blend with burn on line 4 but how can i do this with variables?

linenumber=4
from=blend
to=burn

# a bit extra: escape special characters
# https://stackoverflow.com/questions/407523/escape-a-string-for-a-sed-replace-pattern
from=$(printf '%s\n' "$from" | sed -e 's/[]\/$*.^[]/\\&/g');
to=$(printf '%s\n' "$to" | sed -e 's/[\/&]/\\&/g')

# Note the quoting
sed -i "${line}s/default=\"${from}\",/default=\"${to}\",/"
#        ^^^^^^                                            - used ${line} so that 's' is separate
#                        ^^       ^^          ^^     ^^    - double quotes within double quoting need to be escaped
#      ^                                                 ^ - double quotes so that ${..} are expanded
sed -i '"$var1"s/default="blend",/default="burn",/' $f2

Variables are not expanded within single quotes.

sed -i "$var1"s/default="*"/default="$var2"/ file.txt

Regex is not glob. "* matches zero or more " characters. It does not match anything, * matches zero or more of preceding character or group. A dot . matches anything, so you could default=".*" or better I would go with default="[^"]*".

sed -i ""$var1"s/default="*",/default="$var2",/" file.txt

Use an editor with syntax highlighting. Even stackoverflow syntax highlighting should hint you - " close the other ". To write " within double quotation, escape them "\"".

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • upvoted for making me realize i am still thinking about some things wrongly. not an ideal solution though as i may not know what the initial default value is. – Skydivr Feb 01 '21 at 20:32
  • `may not know what the initial default value is` Then match it with a regex. – KamilCuk Feb 01 '21 at 20:33
  • ok it took me a bit to figure out how to get the starting value into a variable but once i did this worked a charm. thank you sir not just for the right answer but also for helping me think differently. – Skydivr Feb 01 '21 at 21:38
0

To expand the variables, place the sed statement in double quotes as opposed to single quotes. Also since you are using var1 to hold the line to process, place the proceeding substitution statement in {}:

sed -r "$var1{s/(^default=\")(.*)(\",?.*$)/\1$var2\3/}" file1.txt

Also, enable the regular expression interpretation with -r or -E and then split the line into three sections specified in parenthesis and substitute the line for the first section, var2 and then then the third section. Escape any double quotes in the text to change where required.

Raman Sailopal
  • 12,320
  • 2
  • 11
  • 18
  • You don't need braces if there is a single address, though you'll need to disambiguate the variable reference like `${var1}s/..."` – tripleee Feb 01 '21 at 17:31
  • ```sed -ri "$var1{s/(default=\")(.*)(\")/\1$var2\3/}" file1.txt``` This almost gets it done. at least it replaces the necessary bit, but it deletes everything on the line after the match. – Skydivr Feb 01 '21 at 18:36
  • Yeah. Use -i to commit the changes to the file. If the solution meets yours requirements. Please take the time to up vote and accept the answer. – Raman Sailopal Feb 01 '21 at 18:39
  • I've amended the solution. Try it again. – Raman Sailopal Feb 01 '21 at 18:50
  • new solution still drops off the end of line. also removed the ```^``` as the string i am working with is not the actual beginning of line. – Skydivr Feb 01 '21 at 20:27
  • Could really do with knowing the complete line as an example – Raman Sailopal Feb 01 '21 at 20:40
0

Assumptions/provisos:

  • patterns to be searched and replaced can contain any printable characters which means ...
  • said patterns may need to include escape characters to keep from clashing with sed delimters and constructs
  • default=<search_pattern> only shows up once in a line

Sample data:

$ cat file.txt
abcde default=60.0, ABC
12345 default=False, ABC
STUVW default=(0.2, 0.2, 0.3, 1.0), ABC
@#%#@ default="blend", ABC
ABCDE default="/path/to/directory") ABC

One sed idea based on 2 variables (var1 == search / var2 == replacement):

sed -E "s/default=$var1/default=$var2/g" file.txt

Test case #1:

var1='"blend"'
var2='"burn"'
sed -E "s/default=$var1/default=$var2/g" "${infile}"

Generates:

abcde default=60.0, ABC
12345 default=False, ABC
STUVW default=(0.2, 0.2, 0.3, 1.0), ABC
@#%#@ default="burn", ABC                              # modified line
ABCDE default="/path/to/directory") ABC

Test case #2:

var1='\(0.2, 0.2, 0.3, 1.0\)'                          # must escape the parens
var2='[something different = 3.22]'
sed -E "s/default=$var1/default=$var2/g" "${infile}"

Generates:

abcde default=60.0, ABC
12345 default=False, ABC
STUVW default=[something different = 3.22], ABC        # modified line
@#%#@ default="blend", ABC
ABCDE default="/path/to/directory") ABC

Test case #3:

var1='"\/path\/to\/directory"'                         # must escape the forward slashes
var2='"\/a\/new\/directory"'                           # must escape the forward slashes
sed -E "s/default=$var1/default=$var2/g" "${infile}"

Generates:

abcde default=60.0, ABC
12345 default=False, ABC
STUVW default=(0.2, 0.2, 0.3, 1.0), ABC
@#%#@ default="blend", ABC
ABCDE default="/a/new/directory") ABC                  # modified line
markp-fuso
  • 28,790
  • 4
  • 16
  • 36