Bash - 使用 sed 更改配置文件

Posted

技术标签:

【中文标题】Bash - 使用 sed 更改配置文件【英文标题】:Bash - Changing configuration file with sed 【发布时间】:2012-10-10 08:13:08 【问题描述】:

我在使用更改名为“.backup.conf”的配置文件的 shell 脚本时遇到了一些问题。

配置文件如下所示:

inputdirs=(/etc /etc/apm /usr/local)
outputdir="test_outputdir"
backupmethod="test_outputmethod"
loglocation="test_loglocation"`

我的脚本需要更改配置文件变量之一,而最后 3 个变量我没有遇到任何问题。

如果我想将变量 "inputdirs" /etc/ 更改为 /etc/perl,我应该使用什么表达式?

如果我将 echo 与 append 一起使用,它只会将其附加到文件的末尾。

我尝试使用以下格式的 sed: sed -i 's/$inputdirs[$((izbor-1))]/$novi/g' .backup.conf 其中“izbor”是我想从 inputdirs 更改的变量,“novi”是新路径(例如 /etc/perl)。

因此,使用以下配置文件,并使用变量$izbor=1$novi=/etc/perl,我应该将第一个变量inputdirs=/etc更改为/etc/perl 并且变量 inputdirs 最终应该看起来像 inputdirs=(/etc/perl /etc/apm /usr/local)

感谢您的帮助!

【问题讨论】:

Sed 是一个流编辑器。您正在对字符串进行 RegEx 搜索/替换...但尝试对数组进行操作? 如果与 /g 一起使用,sed 不应该在整个文件中搜索条件吗? g 不是这样做的,g 是“全部替换”。但无论如何 - 您的搜索表达式无效。 grymoire.com/Unix/Sed.html#uh-1 您介意纠正它还是建议一些变量?我完全没有想法...... 【参考方案1】:

如果您尝试使用 $izbor 作为索引,它可能希望成为s/// 的标志。假设您的输入与 ^inputdirs=( 匹配(没有空格),您可能会逃脱:

sed -i '/^inputdirs=(/ 
    s/(/(  /; s/)/ )/;   # Insert spaces inside parentheses
    s@ [^ ][^ ]* @ '"$novi@$izbor"'; 
    s/( /(/; s/ )/)/;   # Remove inserted spaces
' .backup.conf

前两个表达式确保括号内有空格, 因此,如果您的输入已经有空格,则可能没有必要。上面有点混淆,但基本上你正在做的替换是这样的:

s@ [^ ][^ ]* @/etc/perl@2

2 标志告诉 sed 仅替换匹配项的第二次出现。这真的很脆弱,因为它在 inputdirs 之前不需要空格,在括号内也不需要空格,并且不处理制表符,但它应该适合你。此外,一些sed 允许将[^ ][^ ]* 更简单地写为[^ ]+,但这并不普遍。

【讨论】:

感谢您的详细解释,但我收到了unexpected EOF while looking for matching ''` 我的错误——已编辑。 izbor" 后面少了一个单引号。 测试它并且它工作,但它在前面添加了一个空格,所以现在它看起来像inputdirs=( /etc/perl/etc/apm /usr/local ) 是的,明确添加了空间以进行匹配。您可以使用-e 's/( /(/' 将其删除。我会将其添加到答案中。 它正在工作!看来我有2个正确答案。非常感谢威廉!【参考方案2】:

你可以试试这个:

enovi="$(printf '%s\n' "$novi" | sed -e 's/[\\&/]/\\&/g')"
izbor1="$(expr "$izbor" - 1)"
sed -rie "s/([(]([^ ]* )$izbor1)[^ )]*/\\1$enovi/" config.txt

命令摘要:

    第一行生成一个变量$enovi,其中包含$novi 的转义内容。基本上,以下字符被转义:&\/。所以/etc/perl 变成了\/etc\/perl。 我们创建一个递减$izbor的新变量。 这是实际的替代表达式。我将分部分解释:
      首先我们匹配括号字符[(]。 我们现在将搜索一系列非空格,后跟一个空格 ([^ ]*)。 此搜索(通过内括号中的分组标识)重复$izbor1 次 ($izbor1) 前面的表达式被分组到一个外括号组中,以便被捕获到一个辅助变量\1中。 我们现在匹配要替换的单词。它由不是空格且不是右括号的字符序列组成(这是为了处理最后一个单词的大小写) 替换由捕获的值\1 组成,后跟我们的新字符串。

希望这会有所帮助 =)

【讨论】:

我收到 sed:-e 表达式 #1,字符 30:`s' 的未知选项 是的,我忘了$novi 是一个路径,所以它混淆了sed。解决方法是在使用字符串之前对其进行转义,因此我更新了帖子以创建一个新变量 $enovi,其中包含 $novi 的转义版本。 这个似乎可行,但 conf 文件中的变量现在看起来像这样:inputdirs=( /etc/apm /usr/local) 但应该看起来像 inputdirs=(*value that i entered* /etc/apm /usr/local) 希望这可以解决所有问题 =)。错误的错误是由三个问题引起的:它不会匹配最后一个参数,因为它没有考虑到该单词可以以)结尾; [(]([^ ]* )$izbor1 周围必须有一个更大的括号组才能捕获所有以前的匹配项; izbor 必须先递减才能使用。 好吧,我不想把它降下来,但输入目录仍然只有(/etc/apm /usr/local):(

以上是关于Bash - 使用 sed 更改配置文件的主要内容,如果未能解决你的问题,请参考以下文章

更改文件名后缀(使用 sed ?)

shell sed修改linux终端的配置文件

shell sed修改linux终端的配置文件

使用 bash、sed、awk 解析像 .ini 这样的文件

Git bash:如何更改 MinTTY 配置文件的存储位置?

如何查找多个文件、检查重复文件并用 bash、sed 脚本替换