【发布时间】:2021-12-18 01:30:07
【问题描述】:
我正在与sed 进行替换,其中替换字符串包含斜杠。这个一般主题之前已经讨论过堆栈溢出。但是,AFAICT,我有一个新的皱纹,之前的问题没有解决。
假设我有一个文件 ENVIRO.tpml,它有几行,其中一行是
Loaded modules: SUPPLY_MODULES_HERE
我想以自动方式将SUPPLY_MODULES_HERE 替换为已加载模块的列表。 (此时,如果有人有比sed 更好的方法,请告诉我!)我在这里的第一个工作是定义一个环境变量并使用sed 将其放入文件中:
> modules=$(module list 2>&1)
> sed "s/SUPPLY_MODULES_HERE/${modules}/" ENVIRO.tmpl > ENVIRO.txt
(需要2>&1,因为module list 将其输出发送到STDERR,原因我无法开始理解。)但是,通常情况下,模块中有斜线。例如
> echo ${modules}
gcc/9.2.0 mpt/2.20
斜杠终止了我的命令,因为sed 无法理解表达式并认为我的替换命令“未终止”。
所以我照常使用其他字符作为命令分隔符:
> modules=$(module list 2>&1)
> sed "s|SUPPLY_MODULES_HERE|${modules}|" ENVIRO.tmpl > ENVIRO.txt
我仍然收到“未终止的 's'”错误。
所以我用单引号代替双引号:
> sed 's|SUPPLY_MODULES_HERE|${modules}|' ENVIRO.tmpl > ENVIRO.txt
现在我没有收到任何错误,但 ENVIRO.txt 中的行看起来像
Loaded modules: ${modules}
不是我所希望的。
所以,AFAICT,我需要双引号来扩展变量,但我需要单引号来使替代分隔符起作用。但我同时需要两者。我怎么得到这个?
更新:下面 Gordon Davisson 的评论触及了问题的根源:“echo ${modules} 可能具有高度误导性”。用 declare -p 检查 $modules 表明它实际上有一个换行符(或更一般地说,某种换行符)。我所做的是添加一个额外的步骤来从变量中提取换行符。有了这种变化,一切正常。另一种方法是说服 sed 用换行符扩展变量并将其替换为文本,但我无法做到这一点。有接盘侠吗?
【问题讨论】:
-
我认为您“不需要单引号来使替代分隔符起作用”。你的例子似乎对我有用。你用那个实际的例子来测试它吗?
modules="gcc/9.2.0 mpt/2.20";echo Loaded modules: SUPPLY_MODULES_HERE | sed "s|SUPPLY_MODULES_HERE|${modules}|"或者你有不同的场景,模块中有管道? -
$modules的实际内容是什么?echo ${modules}can be highly misleading,所以试试declare -p modules | LC_ALL=C cat -v。 -
使用双引号和管道的版本没有明显的问题。预先添加
echo,删除重定向,然后发布该输出,这样我们就可以看到 sed 试图执行的内容。 -
如果您的模板需要执行多个替换或更复杂的操作,那么您可以直接使用 PHP 或 ERB (Ruby) 等模板语言。
-
@GordonDavisson 你可能对我的更新感兴趣。