2

I am doing a research project that requires shell scripting, which I have almost no experience in, although I do have some programming experience. Here is the file in question:

export OMP_NUM_THREADS=12 read controls #inlist directory export MESA_INLIST="/home/nick/mesa-r11701/star/test_suite/rsp_Cepheid_grid/inlist" sed -i -e 's/.*extra_star_job_inlist2_name.*/extra_star_job_inlist2_name = '"'"''$controls"""'"'/i' $MESA_INLIST sed -i -e 's/.*extra_controls_inlist2_name.*/extra_controls_inlist2_name = '"'"''$controls"""'"'/i' $MESA_INLIST 

I am borrowing this file to change the input of this second file /home/nick/mesa-r11701/star/test_suite/rsp_Cepheid_grid/inlist. Specifically the extra_controls_inlist2_name and the extra_star_job_inlist2_name variables (what is after the right side of the equal sign).

! this is the master inlist that MESA reads when it starts. ! This file tells MESA to go look elsewhere for its configuration ! info. This makes changing between different inlists easier, by ! allowing you to easily change the name of the file that gets read. &star_job read_extra_star_job_inlist1 = .true. extra_star_job_inlist1_name = 'inlist_0all' read_extra_star_job_inlist2 = .true. extra_star_job_inlist2_name = 'inlist_3ms' / ! end of star_job namelist &controls read_extra_controls_inlist1 = .true. extra_controls_inlist1_name = 'inlist_0all' read_extra_controls_inlist2 = .true. extra_controls_inlist2_name = 'inlist_3ms' / ! end of controls namelist &pgstar / ! end of pgstar namelist 

I am already familiar with what the export and read commands do. I know that sed is a stream editor that is used for finding and replacing text, which is what my goal with the second file is here. However, what do the -i -e options do here exactly? Why are there so many quotes around $controls$? What do the /.* and the /i of the sed command mean? I tried to do a preliminary search for these online, but I could not find an appropriate answer.

3
  • Did you start with man sed? Commented May 17, 2020 at 16:38
  • @JeffSchaller info sed in this case, as e.g. /i is not explained properly in the GNU sed manual, for whatever reason. Commented May 17, 2020 at 16:54
  • Sure, although the -i and -e would be. I like to see evidence of "searches online" to show self-motivation and the extent of knowledge / where the ignorance starts. Commented May 17, 2020 at 17:18

1 Answer 1

3
  1. -e means "the next command line argument is a sed expression".
  2. -i means "do this edit in-place, i.e. modify the original file". This is option is non-standard and may cause confusion when moving between different sed implementations on different Unix systems. See e.g. How can I achieve portability with sed -i (in-place editing)?
  3. /.* is the start of the regular expression to match the text that is supposed to be substituted. It's actually /, the delimiter for the s/// (substitution) command in sed, and the start of the regular expression .*extra_star_job_inlist2_name.*. The .* by itself means "match any number of any character".

    The .* also occurs at the end of the expression .*extra_star_job_inlist2_name.* and the effect is that any line that contains the string extra_star_job_inlist2_name will be replaced entirly (i.e. the substitution would not just affect the string extra_star_job_inlist2_name on the line).

  4. The /i is, again, the / delimiter for the s/// command in sed followed by a flag for the s/// command. This flag is non-standard, only available in the GNU flavor of sed. The flag makes the matching of the expression case-insensitive. See the GNU sed documentation about this.

  5. The weird quotes around $controls:

    • The sed expression is given in a single quoted string. Since it's a single quoted string, a variable would not be expanded inside it. To insert the value of a variable, the single quoted string must first end. That's the first '.
    • Then, apparently, the author of the code wants to insert a literal single quote. To do that, they quote it: "'". They could also have used \' here.
    • Then follows, for whatever reason, a single quoted empty string, ''
    • Then comes the value of $controls (unquoted).
    • Another empty double quoted string, "".
    • Another quoted single quote, "'".
    • And then the sed expression continues as a single quoted string.

There are a few issues with the quotes around $controls:

  1. There are two empty strings.
  2. The expansion of $controls is unquoted.

A better variation that avoids these issues is

sed -i -e "s/.*extra_star_job_inlist2_name.*/extra_star_job_inlist2_name = '$controls'/i" "$MESA_INLIST" 

i.e. simply use a double quoted string for the whole sed expression (and also properly quote $MESA_INLIST, which, by the way, does not need to be exported with export). This would work as long as the sed expression itself does not contain backslashes or $ characters (these would need to be escaped as \\ and \$).

Or, to shorten it down a bit, use a capture group to capture the string that you want to repeat in the replacement text,

sed -i -e "s/.*\(extra_star_job_inlist2_name\).*/\1 = '$controls'/i" "$MESA_INLIST" 

(and similarly for the other sed command.)

To still use single quotes fore the sed expression, you could do

sed -i -e 's/.*\(extra_star_job_inlist2_name\).*/\1 = '"'$controls'"'/i' "$MESA_INLIST" 

Another optimization would be to combine both calls to sed into a single call:

sed -i -e "s/.*\(extra_star_job_inlist2_name\).*/\1 = '$controls'/i" \ -e "s/.*\(extra_controls_inlist2_name\).*/\1 = '$controls'/i" "$MESA_INLIST" 
1
  • ♦ Thank you for this lucid explanation! Please see my upcoming response below to see if I understand correctly. Commented May 17, 2020 at 17:23

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.