我正在做一个需要 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_name
和extra_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
我已经熟悉export
和read
命令的作用。我知道 sed 是一个流编辑器,用于查找和替换文本,这就是我对第二个文件的目标。然而,这些-i -e
选项到底有什么作用呢?为什么周围有这么多引用$controls$
?sed 命令的the/.*
和 the是什么意思?/i
我尝试在网上进行初步搜索,但找不到合适的答案。
答案1
-e
意思是“下一个命令行参数是一个sed
表达式”。-i
意思是“进行此编辑到位,即修改原始文件”。此选项是非标准的,在sed
不同 Unix 系统上的不同实现之间移动时可能会导致混乱。参见例如如何使用 sed -i (就地编辑)实现可移植性?/.*
是正则表达式的开头,用于匹配要替换的文本。它实际上是中(替换)命令/
的分隔符,也是正则表达式的开始。其本身意味着“匹配任意数量的任意字符”。s///
sed
.*extra_star_job_inlist2_name.*
.*
也
.*
出现在表达式的末尾.*extra_star_job_inlist2_name.*
,其效果是包含该字符串的任何行都extra_star_job_inlist2_name
将被完全替换(即替换不仅仅影响extra_star_job_inlist2_name
该行上的字符串)。/i
同样,它是命令/
的分隔符,后跟一个s///
sed
旗帜为s///
命令。该标志是非标准的,仅在 GNU 风格的sed
.该标志使表达式的匹配不区分大小写。看GNUsed
文档对这个。周围奇怪的引言
$controls
:- 该
sed
表达式以单引号字符串给出。由于它是单引号字符串,因此变量不会在其中扩展。要插入变量的值,单引号字符串必须首先结束。这是第一个'
。 - 然后,显然,代码的作者想要插入一个文字单引号。为此,他们引用了它:
"'"
。他们也可以在这里使用\'
。 - 然后,无论出于何种原因,后面都是一个单引号空字符串,
''
- 然后是(未引用)的值
$controls
。 - 另一个空双引号字符串,
""
. - 另一个引用的单引号,
"'"
. - 然后
sed
表达式继续作为单引号字符串。
- 该
周围的报价存在一些问题$controls
:
- 有两个空字符串。
- 的扩展
$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"