使用bash编辑包含节的配置文件
我正在编写bash脚本来更改配置文件。配置文件包含节头,每个节可能包含相同的键/值对 示例配置文件:使用bash编辑包含节的配置文件,bash,Bash,我正在编写bash脚本来更改配置文件。配置文件包含节头,每个节可能包含相同的键/值对 示例配置文件: Header one key value key2 foobar Header two key bar 我想替换特定节标题的键值,而不在不同节上触碰同一个键。例如,用一些任意值替换“头1/键”的值“值”,而不更改“头2/键”的值栏 实际的节标题遵循示例中提供的模式(一些固定单词+非固定部分) A提出了使用sed进行价值置换的解决方案: # Set a configuration v
Header one
key value
key2 foobar
Header two
key bar
我想替换特定节标题的键值,而不在不同节上触碰同一个键。例如,用一些任意值替换“头1/键”的值“值”,而不更改“头2/键”的值栏
实际的节标题遵循示例中提供的模式(一些固定单词+非固定部分)
A提出了使用sed进行价值置换的解决方案:
# Set a configuration value
# Args:
# 1) The config key
# 2) The new value
# 3) The config file
function set_config_value() {
sed -i "s/^\s*($1\s*\).*\$/\1$2/" $3
}
但是我不知道如何将替换限制在配置文件的某个部分
我想提出一个类似于的解决方案
# Set a configuration value
# Args:
# 1) The config key
# 2) The new value
# 3) The config section header
# 4) The config file
function set_config_value() {
???
}
编辑:
有关实际配置文件的问题:假设在设置值时节标题的整个文本都是已知的。无论它被称为“头一”、“foo”或“foobar”
编辑2:
Sed可能不是执行此类任务的最佳工具。使用awk,假设键值对行以空格开头:
function set_confg_value() {
awk -i inplace -v section="$1" -v key="$2" -v value="$3" '
BEGIN {
in_section = 0
}
# Set the in_section flag when entering the requested section
$0~section {
in_section = 1
}
# Process matched section
$0~"^\\s+"key {
if (in_section) {
print " "$1" "value
skip = 1
}
}
# Reset in_section flag
$0~"(?!"section")^\\S" {
in_section = 0
}
# Print the rest
/.*/ {
if (skip)
skip = 0
else
print $0
}
' "$4"
}
不能像sed那样使用基于行的搜索结束替换。您需要记住上下文,即您在文件中的位置。你必须逐行阅读文件,并记录你在哪个部分。如果在正确的部分,请找到键并替换该值
#!/bin/bash
set -eu
# Set a configuration value
# Args:
# 1) The config key
# 2) The new value
# 3) The config section header
# 4) The config file
function set_config_value() {
key="$1"
new="$2"
header="$3"
file="$4"
tmpfile=$(mktemp)
headerRegex='^Header (\S+)$'
keyRegex="\s*$key\s*"
insection=""
IFS=''
while read -r line
do
# Check for the next header
if [[ "$line" =~ $headerRegex ]]
then
# Is it the one we're looking for?
if [ "$header" == "${BASH_REMATCH[1]}" ]
then
insection="1"
else
insection=""
fi
fi
# If we are in the right section:
if [ -n "$insection" ]
then
# and we look at the right key
if [[ "$line" =~ $keyRegex ]]
then
# change it
line=" $key $new"
fi
fi
# Print the line, either as it was or modified
echo "$line" >> "$tmpfile"
done < "$file"
mv "$tmpfile" "$file"
}
set_config_value "key" "new value" "two" "in.cfg"
您当前的尝试有一些问题
# Your code
sed -i "s/^\s*($1\s*\).*\$/\1$2/" $3
在$1
之后,如果您至少需要一个空格(您不希望与键2匹配),请使用“+”。如果要保留替换后的第一个空格,请将其放入匹配项中。
可能短键后会有额外的空格,所以在匹配中也要将空格放在键后。
您不想匹配
$
。带反斜杠的是一个字符。您不需要匹配行尾,*
将匹配所有内容,直到行尾。一个名称中有空格的配置文件怎么样?报价
$3
而且
\s
在普通sed
中不起作用。试试-r
我删除了
-I
,因此您可以在不更改文件的情况下进行测试:
sed -r "s/^(\s*$1\s+).*$/\1$2/" "$3"
如果要将此代码限制为一个节,请使用/start/,/end/
。你怎么知道某个东西是标题?在您的示例中,标题行称为header,但在实际配置文件中并非如此。当标题看起来像[section]
时,请更改下面的解决方案。beneat的解决方案假定所有不以空格开头的行都是一个标题
# Set a configuration value
# Args:
# 1) The config key
# 2) The new value
# 3) The config section header
# 4) The config file
function set_config_value() {
key="$1"
val="$2"
header="$3"
file="$4"
# first test this without the -i flag
sed -ir "/^${header}$/,/^[^\s]/ s/^(\s*${key}\s+).*$/\1${val}/" "${file}"
}
此解决方案应适用于您的示例配置,但当${key}
或${value}
具有特殊字符(请尝试key=/
)时,此解决方案将失败。您应该使用一种不试图理解给定字符串的解决方案。我的第一个想法是
awk
,但请自己选择。查看。除非您描述配置文件的结构,否则此问题的任何答案都将基于假设,并且可能无法与实际输入一起工作
# Set a configuration value
# Args:
# 1) The config key
# 2) The new value
# 3) The config section header
# 4) The config file
function set_config_value() {
key="$1"
val="$2"
header="$3"
file="$4"
# first test this without the -i flag
sed -ir "/^${header}$/,/^[^\s]/ s/^(\s*${key}\s+).*$/\1${val}/" "${file}"
}