使用Shell脚本生成配置文件的6种方法

 更新时间:2025年12月31日 09:08:25   作者:大聪明-PLUS  
根据模板准备配置文件是一项非常常见的系统管理任务,实现此任务的方法有很多种,每种方法都有其自身的优势,本文将介绍如何使用 shell 脚本来完成此操作,需要的朋友可以参考下

学习任务

我们将以解决一个典型问题为例进行研究,该问题需要创建一个 shell 脚本来生成包含节点网络堆栈设置的配置文件。我们假设待配置的节点只有一个名为“ens33”的网络接口。该脚本必须允许指定静态 IP 地址、子网掩码和默认网关。

基于以上考虑,我们得到以下配置文件模板:

自动 ens33
接口 ens33 inet 静态
地址IP_ADDRESS_VALUE
子网掩码NETMASK_VALUE
网关DEFAULT_GATEWAY_VALUE

为了进一步举例说明,我们假设 IP 地址设置为 192.168.0.10,子网掩码设置为 255.255.255.0,默认网关设置为 192.168.0.1。

选项 1. 将模板放置在脚本中,使用标准工具生成输出

解决这个问题的最简单方法(新手开发者经常使用的方法)是将模板放在脚本主体中,并使用局部变量作为占位符值。

#!/bin/bash
 
IP="192.168.0.10"
NETMASK="255.255.255.0"
GATEWAY="192.168.0.1"
 
TEMPLATE="$(
cat << EOF
auto ens33
iface ens33 inet static
address $IP
netmask $NETMASK
gateway $GATEWAY
EOF
)"
 
echo -e "$TEMPLATE"

脚本的运行结果(以及所有后续脚本的运行结果)将如下所示:

自动 ens33
接口 ens33 inet 静态
地址 192.168.0.10
子网掩码 255.255.255.0
网关 192.168.0.1

这个方案各方面都很好,唯一的不足之处在于,修改模板时可能出现的人为错误(例如拼写错误或其他错误)会导致脚本“崩溃”。因此,更合理的架构方案是将脚本和模板分别放在不同的文件中。

细心的读者可能会注意到,我们在脚本主体中设置了变量值,这意味着要生成具有不同设置的下一个配置文件,仍然需要修改脚本。没错,确实如此,但这是为了简化操作而有意为之。当然,我们完全可以扩展脚本,例如,添加一个用户界面,让用户可以通过控制台输入变量值。

选项 2. 将模板放在外部文件中,并使用 envsubst 填充它

让我们创建一个名为“template.txt”的模板文件,内容如下:

自动 ens33
接口 ens33 inet 静态
地址 $IP
子网掩码 $NETMASK
网关 $GATEWAY

#!/bin/bash
 
export IP="192.168.0.10"
export NETMASK="255.255.255.0"
export GATEWAY="192.168.0.1"
 
envsubst  < template.txt

选项 3. 将模板放在外部文件中,并使用 sed 工具填充它。

该工具sed允许您将字符串相互替换。为了避免重写模板,我们将搜索与变量名($IP、$NETMASK、$GATEWAY)对应的字符串,并将其替换为相应的值。请注意,要搜索字符串“$IP”,我们需要转义“$”字符,并搜索字符串“\$IP”(其他变量也适用相同的规则)。

#!/bin/bash
 
IP="192.168.0.10"
NETMASK="255.255.255.0"
GATEWAY="192.168.0.1"
 
cat template.txt | sed "s/\$IP/$IP/" |
                sed "s/\$NETMASK/$NETMASK/" |
                sed "s/\$GATEWAY/$GATEWAY/"

选项 4. 将模板放在外部文件中,并使用 awk 填充它

这个选项在概念上与前一个选项类似,只是sed我们用代替awk,这会稍微影响脚本列表。

#!/bin/bash
 
IP="192.168.0.10"
NETMASK="255.255.255.0"
GATEWAY="192.168.0.1"
 
cat template.txt |
 awk -v replace_str="$IP"      '{ gsub( /\$IP/ ,      replace_str ); print }' |
 awk -v replace_str="$NETMASK" '{ gsub( /\$NETMASK/ , replace_str ); print }' |
 awk -v replace_str="$GATEWAY" '{ gsub( /\$GATEWAY/ , replace_str ); print }'

选项 5. 将模板放在外部文件中,并使用 eval 函数填充它

此选项与之前的选项不同之处在于,它不使用任何外部工具,而只使用内置命令eval。用于生成模板的脚本eval如下所示:

#!/bin/bash
 
IP="192.168.0.10"
NETMASK="255.255.255.0"
GATEWAY="192.168.0.1"
 
TEMPLATE=$(< template.txt)
 
eval "echo -e \"$TEMPLATE\""

你可能想知道我们为什么需要它eval?这个例子会帮助你理解:

#!/bin/bash
 
VAR="A"
 
TEMPLATE_LOCAL="VAR=$VAR"
TEMPLATE_FILE="$( < template_file.txt)"
 
# VAR=$VAR
 
echo -e "$TEMPLATE_LOCAL"
 
# VAR=A
echo -e "$TEMPLATE_FILE"
 
# VAR=$VAR
eval "echo -e \"$TEMPLATE_FILE\""

如您所见,eval这使您能够克服 Shell 的一些特性,这些特性会导致脚本对同一数据的解释因数据是在脚本主体中指定还是从外部文件加载而有所不同。现在让我们来谈谈使用此功能提供的特性和功能eval

首先需要注意的是,需要在模板文件中转义特殊字符。例如,`" " "` 应替换为 `" \"`。

使用此功能的第二个特性eval是能够在模板中编写代码。这使您可以构建复杂的模板,这些模板不仅可以替换值,还可以根据指定的条件输出(或不输出)整个部分。

为了演示此功能,我们将通过添加一个可选的第二个接口设置“ens37”来使我们的教程更加复杂。这意味着“ens33”将始终配置,而“ens37”仅在必要时配置。使用后,eval配置文件模板(eval_template.txt)将如下所示:

auto ens33
iface ens33 inet static
address $ENS33_IP
netmask $ENS33_NETMASK
gateway $ENS33_GATEWAY

$(
if [[ (-n ${ENS37_IP}) && (-n ${ENS37_NETMASK}) ]]; then
cat << EOF
auto ens37
iface ens37 inet static
address $ENS37_IP
netmask $ENS37_NETMASK
EOF
fi
)

我们将对之前编写的脚本进行一些关于变量名称的细微修改。除此之外,所有内容基本保持不变。

#!/bin/bash
 
ENS33_IP="192.168.0.10"
ENS33_NETMASK="255.255.255.0"
ENS33_GATEWAY="192.168.0.1"
 
ENS37_IP="10.0.0.10"
ENS37_NETMASK="255.255.0.0"
 
TEMPLATE=$(< eval_template.txt)
 
eval "echo -e \"$TEMPLATE\""

脚本运行结果:

自动配置 ens33
接口 ens33 inet 静态
地址 192.168.0.10
子网掩码 255.255.255.0
网关 192.168.0.1

自动配置 ens37
接口 ens37 inet 静态
地址 10.0.0.10
子网掩码 255.255.0.0

除了潜在的风险之外,在模板中编写代码也存在风险。攻击者可以秘密修改模板,添加恶意代码,这些代码会在生成下一个配置文件时执行。你非但无法通过自动化日常任务来简化工作,反而会面临清理黑客攻击后果的棘手问题。

在上面的例子中,模板文件非常小,可以快速扫描(经过适当的训练)。但如果模板很大,几乎不可能找到恶意代码。而且,不断检查模板是否存在未经授权的修改本身就是一个糟糕的主意。

选项 6. 将模板放在外部文件中,并使用 Bash 的内置功能填充它

另一个纯粹的 Shell 变体,其理念与awk或类似。只是这里我们使用shell的内置工具sed进行字符串搜索和替换。

#!/bin/bash
 
IP="192.168.0.10"
NETMASK="255.255.255.0"
GATEWAY="192.168.0.1"
 
TEMPLATE="$(< template.txt)"
 
TEMP="${TEMPLATE/\$NETMASK/$NETMASK}"
TEMP="${TEMP/\$IP/$IP}"
TEMP="${TEMP/\$GATEWAY/$GATEWAY}"
 
echo -e "$TEMP"

结论

我们已经了解了六种使用 Shell 脚本构建配置文件的方法。你应该选择哪一种呢?当然是选择你最喜欢的!

在其他条件相同的情况下,可以考虑envsubst使用 `shell` 脚本。它解决了基本问题,而且使用起来非常简洁。但是,出于eval安全考虑,最好避免使用它。

相关文章

  • awk脚本统计一组单词中字母出现最多最少频率

    awk脚本统计一组单词中字母出现最多最少频率

    这篇文章主要介绍编写一个 awk 脚本来找到一组单词中出现次数最多(和最少)的单词频率,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • linux禁止普通用户切换至root用户的实例讲解

    linux禁止普通用户切换至root用户的实例讲解

    今天小编就为大家分享一篇linux禁止普通用户切换至root用户的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-06-06
  • Shell编程 Bash引号的那点事

    Shell编程 Bash引号的那点事

    促使我想写这个系列的文章,是因为看到总有人提到相同的问题,犯相同的错误,曾经我也是这么过来的,不忍心看到后面还有人经常这么曲折的过来
    2015-01-01
  • shell script获取文件名或者目录名称的方法

    shell script获取文件名或者目录名称的方法

    本文主要介绍了shell script获取文件名或者目录名称的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Shell命令行中特殊字符与其转义详解(去除特殊含义)

    Shell命令行中特殊字符与其转义详解(去除特殊含义)

    这篇文章主要给大家详细介绍了Shell命令行中特殊字符与其转义(去除特殊含义)的相关资料,文中介绍的很详细,相信对大家具有一定的参考价值,有需要的朋友们下面来一起看吧。
    2017-02-02
  • Shell实现识别物理cpu个数、核心数

    Shell实现识别物理cpu个数、核心数

    这篇文章主要介绍了Shell实现识别物理cpu个数、核心数,本文还介绍了判断是否为超线程的功能,需要的朋友可以参考下
    2014-12-12
  • linux 中more、less 和 most 的区别

    linux 中more、less 和 most 的区别

    more 是一个老式的、基础的终端分页阅读器,它可以用于打开指定的文件并进行交互式阅读。这篇文章主要给大家介绍linux 中more、less 和 most 的区别,感兴趣的朋友跟随小编一起看看吧
    2018-11-11
  • Shell脚本实现自动检测修改最快的Ubuntu软件源

    Shell脚本实现自动检测修改最快的Ubuntu软件源

    这篇文章主要介绍了Shell脚本实现自动检测修改最快的Ubuntu软件源,本文先是讲解了实现的思路,并给了实现脚本源码,需要的朋友可以参考下
    2014-10-10
  • nginx日志切割shell脚本

    nginx日志切割shell脚本

    nginx的日志文件没有rotate功能。如果你不处理,日志文件将变得越来越大,还好我们可以写一个nginx日志切割脚本来自动切割日志文件
    2014-03-03
  • Shell脚本实现FTP自动上传和下载文件

    Shell脚本实现FTP自动上传和下载文件

    本文主要介绍了Shell脚本实现FTP自动上传和下载文件,主要内容包括批量下载脚本代码、下载单个文件脚本代码、登录FTP实现上传文件功能、上传单个文件脚本代码等
    2023-08-08

最新评论