GNU sed - 基于变量参数创建现有模板的修改版本

GNU sed - 基于变量参数创建现有模板的修改版本

这个问题是关于使用 渲染模板sed

我有模板文件nginx_app

server {
    root ${drt}/${domain}/;
    server_name ${domain} www.${domain};
}

我在另一个脚本中使用该文件:

#!/bin/bash
domain="$1" && test -z ${domain} && return
sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"

当然,目的是有一个example.com.conf作为渲染模板,基于。nginx_app


考虑上面的代码:

sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"

据我了解,这段代码执行以下操作:

  1. ${domain}它根据${1}( ) 的脚本参数更改(尚未展开的)字符串example.com,这是在内存,但不更改nginx_app文件本身。
  2. nginx_app通过将渲染版本重定向到/etc/nginx/sites-available/${domain}.conf.

假设我在这里是准确的,我必须说,从代码来看,这些操作对我来说非常不直观。我对该代码的描述准确吗?

如果我的描述不够准确,请更正。

答案1

是的,您对文本第二部分的理解是正确的。

sed与许多其他 Unix 工具一样,可以说它的作用就像筛选。过滤器接受输入、修改它并产生输出。在许多情况下,执行过滤的实用程序甚至可能不知道它正在读取或写入文件。事实上,它可以直接从另一个过滤器实用程序读取或写入。这对于实用程序本身是透明的,并且由 shell 负责设置。

忽略以下不必要使用的事实cat

cat <file | sed 's/^\([^=]*\)=\(.*\)$/#\1=\2 # old/' | tr -s ' ' >newfile

上面的实用程序都不知道从文件中读取或写入文件。 cat从其读取标准输入流(shell 安排其中包含来自 的数据file),可能一次一行,并将其输出写入其标准输出流(无需修改)。

sed读取自它是标准输入流(shell 已将其连接到 的输出流cat)对每行输入进行一些修改,并将结果写入其标准输出流(连接到tr)。

tr也只是写入标准输出,但 shell 以输出进入文件的方式设置重定向newfile

在此过程的每个步骤中,每个实用程序可能只保存通过管道的最低限度必需的数据(在 RAM 中分配的缓冲区中)。这意味着newfile在文件中的数据file被完全读取之前,结果可能会开始写入(在本示例中)。


你的具体例子:

sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"

发生了什么:

  1. shell 解析命令行并查找变量和重定向。

  2. 文件/etc/nginx/sites-available/${domain}.conf$domain扩展为该变量的值)如果存在则被截断(或清空),如果不存在则创建为空文件。

  3. 该实用程序使用操作数(其中已扩展为其值,但尚未扩展,因为已使用 进行转义)和sed来调用。 shell 还会将标准输出连接到您要重定向到的文件。s/\${domain}/${1}/g$1${domain}$\nginx_appsed

  4. 由于sed有两个操作数,它会假设第二个操作数是要读取的文件。它打开它并逐行读取它,同时在第一个操作数中应用编辑命令。

  5. 任何输出都会进入您重定向到的文件。


既然人们提到sed -i

-i使sedsed给定文件执行更改的标志到位,也就是说,它不会写入其标准输出,但其更改的结果将反映在用于输入的同一文件中。

在内部,sed通过写入临时文件它稍后用它替换原始文件。

-i标志采用一个(对于 GNUsed和该实用程序的一些其他实现是可选的,对于其他实用程序是强制的)参数:

sed -i .bak '...some sed script...' filename

这会导致使用给定字符串作为新文件名后缀来备份原始文件。

我通常会尝试阻止人们使用-iwith sed,原因如下:

相反,我建议人们做一些类似的事情

sed '...some sed script...' file >file-new && mv file-new file

&& mv...并且仅在sed零件经过正确测试后才添加零件。

意思&& mv是“如果上一个命令成功终止(没有错误),则重命名该文件”。

答案2

如果没有该-i标志,任何命令的结果sed都将写入标准输出。

在本例中,您将标准输出重定向到另一个文件 ( /etc/nginx/sites-available/${domain}.conf)。

答案3

听起来您好像在问为什么必须将输出重定向到文件中而不是sed直接写入该文件。如果是这样,有几个原因。

  1. 实际上,您可以通过-i的参数来做到这一点sed
  2. 这不是默认行为,因为它不遵循设计与其他程序对话的程序的常见 UNIX 哲学(https://en.wikipedia.org/wiki/Unix_philosophy)。
    许多 UNIX shell 实用程序背后的想法是将它们链接在一起 ( foo | bar | baz)。这允许您对数据执行复杂的处理,而无需在每个步骤之间将其缓冲到磁盘。

相关内容