有人可以在这里向我解释 sed 命令的语法吗?

有人可以在这里向我解释 sed 命令的语法吗?

我正在做一个需要 shell 脚本编写的研究项目,尽管我确实有一些编程经验,但我几乎没有经验。这是有问题的文件:

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

我借用这个文件来更改第二个文件的输入/home/nick/mesa-r11701/star/test_suite/rsp_Cepheid_grid/inlist。特别是extra_controls_inlist2_nameextra_star_job_inlist2_name变量(等号右侧后面的内容)。

! 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

我已经熟悉exportread命令的作用。我知道 sed 是一个流编辑器,用于查找和替换文本,这就是我对第二个文件的目标。然而,这些-i -e选项到底有什么作用呢?为什么周围有这么多引用$controls$?sed 命令的the/.*和 the是什么意思?/i我尝试在网上进行初步搜索,但找不到合适的答案。

答案1

  1. -e意思是“下一个命令行参数是一个sed表达式”。
  2. -i意思是“进行此编辑到位,即修改原始文件”。此选项是非标准的,在sed不同 Unix 系统上的不同实现之间移动时可能会导致混乱。参见例如如何使用 sed -i (就地编辑)实现可移植性?
  3. /.*是正则表达式的开头,用于匹配要替换的文本。它实际上是中(替换)命令/的分隔符,也是正则表达式的开始。其本身意味着“匹配任意数量的任意字符”。s///sed.*extra_star_job_inlist2_name.*.*

    .*出现在表达式的末尾.*extra_star_job_inlist2_name.*,其效果是包含该字符串的任何行都extra_star_job_inlist2_name将被完全替换(即替换不仅仅影响extra_star_job_inlist2_name该行上的字符串)。

  4. /i同样,它是命令/的分隔符,后跟一个s///sed旗帜s///命令。该标志是非标准的,仅在 GNU 风格的sed.该标志使表达式的匹配不区分大小写。看GNUsed文档对这个。

  5. 周围奇怪的引言$controls

    • sed表达式以单引号字符串给出。由于它是单引号字符串,因此变量不会在其中扩展。要插入变量的值,单引号字符串必须首先结束。这是第一个'
    • 然后,显然,代码的作者想要插入一个文字单引号。为此,他们引用了它:"'"。他们也可以在这里使用\'
    • 然后,无论出于何种原因,后面都是一个单引号空字符串,''
    • 然后是(未引用)的值$controls
    • 另一个空双引号字符串,"".
    • 另一个引用的单引号,"'".
    • 然后sed表达式继续作为单引号字符串。

周围的报价存在一些问题$controls

  1. 有两个空字符串。
  2. 的扩展$controls未加引号。

避免这些问题的更好的变体是

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

即只需对整个sed表达式使用双引号字符串(并且也正确引用$MESA_INLIST,顺便说一句,不需要使用 导出export)。只要sed表达式本身不包含反斜杠或$字符(这些需要转义为\\and \$),这就可以工作。

或者,要稍微缩短它,请使用捕获组捕获要在替换文本中重复的字符串,

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

(对于其他sed命令也类似。)

要在表达式前仍然使用单引号sed,您可以这样做

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

另一种优化是将两个调用合并sed为一个调用:

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

相关内容