2

I have a script that has a $variable storing a text with an undetermined number of lines. Let's say I've named it script.bash and it's located in $HOME:

#!/bin/bash

# commands on the beginning of my script

variable='Lorem Ipsum is simply dummied 
text of the printing and 
typesetting industry. Lorem Ipsum has been the
industry standard dummy text ever since the 1500s'

# commands at the end of my script

I'd like to create a new script that will change the text in variable on script.bash. The idea of the code would be something like this:

#!/bin/bash

file="$HOME/script.bash"
mynewvariable='one
two
three'

substitute_everything_inside_variable () {
    # code
}

substitute_everything_inside_variable "$mynewvariable" "$file"

As long as it was only a single line it could work substituting the entire row by a new one using sed like the following:

sed -i "5s/.*/$mynewvariable/" "$HOME/script.bash" 

But considering I need to substitute everything inside the single quotes (and the number of lines of the text inside it is variable) I don't see how I could do it using command-line tools. Is there a way of doing it without reading and interpreting what happens in every line?

3
  • Have you considered putting the contents of $variable into a file (e.g. vfile.txt) and then having your shell script do something like variable="$(cat vfile.txt)"? It's much easier to replace the entire contents of a file than to change a multi-line quoted string inside a file with other stuff you don't want to break.
    – cas
    Aug 30, 2019 at 2:35
  • @cas After thinking for a while I've realized that leaving variables inside files as you suggested works perfectly for what I'm doing!! Thanks! I wouldn't have thought of that by myself now. Aug 30, 2019 at 7:59
  • glad it helped. i'll put that in answer.
    – cas
    Aug 30, 2019 at 8:08

3 Answers 3

2

It is much easier to replace the entire contents of a file than to change a multi-line quoted string inside a file containing lots of other stuff you don't want to break.

Try putting the contents of $variable into a file (e.g. vfile.txt), and have your shell script do something like variable="$(cat vfile.txt)".

You can then use any method you want to replace or modify vfile.txt.

0

Sed has commands other than s. You can look for the starting line, delete all lines until the last part of the value, and insert the new value. It's tricky to get the quoting right though — note that s/…/$mynewvariable/ fails not only with newlines, but also with ', \ and /. It's easier to do it in Perl.

If the file isn't too large to fit in memory, tell Perl to read the whole file, rather than break it up line by line. Untested.

mynewvariable=$mynewvariable perl -0777 -i -p -e '
    $replacement = $ENV{mynewvariable};
    $replacement =~ s/\x27/\x27\\\x27\x27/g;
    s/^variable=\x27(?:[^\x27]|\x27\\\x27\x27)*\x27/$replacement/;
' "HOME/script.bash"

Explanations:

  • perl -0777 -i -p runs the Perl program on the content of the file, then replaces the file. -0777 means to process the whole file in one go, rather than line by line.
  • I pass the variable through the environment because splicing it into the Perl program would cause it to be interpreted as Perl code rather than a string (it's the same reason why sed s/…/$mynewvariable/ doesn't work).
  • \x27 is a single quote (I put the Perl code inside single quotes so I can't use a single quote inside).
  • $replacement =~ … replaces ' in the value by '\'' which stands for a ' inside a single-quoted shell string literal.
  • (?:[^\x27]|\x27\\\x27\x27) matches either '\'' or any character that isn't '.
1
  • Thanks for the detailed explanation... But I didn't manage to run it successfully, it executes but nothing happens on the script.bash file. (There's a typo on the $HOME variable at the end of your answer) Aug 30, 2019 at 8:03
0

Since you know the line number of the variable where it is located in the script.bash file, you can do this :

#!/bin/bash
file="$HOME/script.bash"
mynewvariable='one
two
three'

substitute_everything_inside_variable () {
    tmpf=$(mktemp)
    printf '%s\n' "$1" |
    sed -e "s/'/'\\\''/g" -e 1s/^/variable=\'/ -e \$s/\$/\'/ > "$tmpf"
    sed -i -e "4r $tmpf"  -e '5s/^/#/' "$2"
    rm -f "$tmpf"
}

substitute_everything_inside_variable "$mynewvar" "$file"
#### eof #####

This way you avoid the vagaries of quoting and the unknown line span of the $variable.

HTH

2
  • Hi, I've tried running this script but it's inserting $mynewvariable on the line that I've predetermined only. It's not substituting the text inside the quotes... Aug 30, 2019 at 8:06
  • When I posted the first solution I was in the bus so cudn't test what i wrote. I have posted an amended version which should work. Aug 30, 2019 at 14:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.