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 更改配置文件的主要内容,如果未能解决你的问题,请参考以下文章
使用 bash、sed、awk 解析像 .ini 这样的文件