【发布时间】:2010-03-17 18:18:26
【问题描述】:
我正在编写一个 bash 脚本来修改一个包含一堆键/值对的配置文件。如何读取密钥并找到值并可能对其进行修改?
【问题讨论】:
-
我试图在这里回答这个问题stackoverflow.com/a/47509618/3343801
我正在编写一个 bash 脚本来修改一个包含一堆键/值对的配置文件。如何读取密钥并找到值并可能对其进行修改?
【问题讨论】:
暗中修改单个值:
sed -c -i "s/\($TARGET_KEY *= *\).*/\1$REPLACEMENT_VALUE/" $CONFIG_FILE
假设目标键和替换值不包含任何特殊的正则表达式字符,并且您的键值分隔符是“=”。请注意,-c 选项取决于系统,您可能需要省略它才能执行 sed。
有关如何进行类似替换的其他提示(例如,当 REPLACEMENT_VALUE 中包含“/”字符时),there are some great examples here。
【讨论】:
ssh [opts] [user@]hostname command 将登录然后运行给定的命令。如果命令足够复杂,您可能希望将其存储在远程脚本中,这样您就可以运行ssh <host> path/to/script。
sed -i '' "s...." $CONFIG_FILE
$TARGET_KEY 之前添加^,否则如果您有两个键,例如even=2 和noteven=1,您最终会同时更改两者。
希望这对某人有所帮助。我创建了一个独立的脚本,它需要各种配置处理。
#!/bin/bash
CONFIG="/tmp/test.cfg"
# Use this to set the new config value, needs 2 parameters.
# You could check that $1 and $2 is set, but I am lazy
function set_config(){
sudo sed -i "s/^\($1\s*=\s*\).*\$/\1$2/" $CONFIG
}
# INITIALIZE CONFIG IF IT'S MISSING
if [ ! -e "${CONFIG}" ] ; then
# Set default variable value
sudo touch $CONFIG
echo "myname=\"Test\"" | sudo tee --append $CONFIG
fi
# LOAD THE CONFIG FILE
source $CONFIG
echo "${myname}" # SHOULD OUTPUT DEFAULT (test) ON FIRST RUN
myname="Erl"
echo "${myname}" # SHOULD OUTPUT Erl
set_config myname $myname # SETS THE NEW VALUE
【讨论】:
假设您有一个 key=value 对的文件,可能在 = 周围有空格,您可以使用 awk 随意删除、就地修改或附加键值对,即使键或值包含特殊的正则表达式序列:
# Using awk to delete, modify or append keys
# In case of an error the original configuration file is left intact
# Also leaves a timestamped backup copy (omit the cp -p if none is required)
CONFIG_FILE=file.conf
cp -p "$CONFIG_FILE" "$CONFIG_FILE.orig.`date \"+%Y%m%d_%H%M%S\"`" &&
awk -F '[ \t]*=[ \t]*' '$1=="keytodelete" { next } $1=="keytomodify" { print "keytomodify=newvalue" ; next } { print } END { print "keytoappend=value" }' "$CONFIG_FILE" >"$CONFIG_FILE~" &&
mv "$CONFIG_FILE~" "$CONFIG_FILE" ||
echo "an error has occurred (permissions? disk space?)"
【讨论】:
sed "/^$old/s/\(.[^=]*\)\([ \t]*=[ \t]*\)\(.[^=]*\)/\1\2$replace/" configfile
【讨论】:
所以我不能对此表示赞赏,因为它结合了 stackoverflow 的答案和来自 irc.freenode.net #bash 频道的帮助,但是现在这里有 bash 函数来设置和读取配置文件值:
# https://stackoverflow.com/a/2464883
# Usage: config_set filename key value
function config_set() {
local file=$1
local key=$2
local val=${@:3}
ensureConfigFileExists "${file}"
# create key if not exists
if ! grep -q "^${key}=" ${file}; then
# insert a newline just in case the file does not end with one
printf "\n${key}=" >> ${file}
fi
chc "$file" "$key" "$val"
}
function ensureConfigFileExists() {
if [ ! -e "$1" ] ; then
if [ -e "$1.example" ]; then
cp "$1.example" "$1";
else
touch "$1"
fi
fi
}
# thanks to ixz in #bash on irc.freenode.net
function chc() { gawk -v OFS== -v FS== -e 'BEGIN { ARGC = 1 } $1 == ARGV[2] { print ARGV[4] ? ARGV[4] : $1, ARGV[3]; next } 1' "$@" <"$1" >"$1.1"; mv "$1"{.1,}; }
# https://unix.stackexchange.com/a/331965/312709
# Usage: local myvar="$(config_get myvar)"
function config_get() {
val="$(config_read_file ${CONFIG_FILE} "${1}")";
if [ "${val}" = "__UNDEFINED__" ]; then
val="$(config_read_file ${CONFIG_FILE}.example "${1}")";
fi
printf -- "%s" "${val}";
}
function config_read_file() {
(grep -E "^${2}=" -m 1 "${1}" 2>/dev/null || echo "VAR=__UNDEFINED__") | head -n 1 | cut -d '=' -f 2-;
}
起初我使用的是公认答案的 sed 解决方案:https://stackoverflow.com/a/2464883/2683059
但是,如果值有 / 字符,它会中断
【讨论】:
一般来说,使用 grep 和剪切很容易提取信息:
cat "$FILE" | grep "^${KEY}${DELIMITER}" | cut -f2- -d"$DELIMITER"
要更新,您可以执行以下操作:
mv "$FILE" "$FILE.bak"
cat "$FILE.bak" | grep -v "^${KEY}${DELIMITER}" > "$FILE"
echo "${KEY}${DELIMITER}${NEWVALUE}" >> "$FILE"
这显然不会保持键值对的顺序。添加错误检查以确保您不会丢失数据。
【讨论】:
FILE,那么您的解决方案将丢失FILE(必须手动将FILE.bak 重命名为FILE恢复。)
我已经这样做了:
new_port=$1
sed "s/^port=.*/port=$new_port/" "$CONFIG_FILE" > /yourPath/temp.x
mv /yourPath/temp.x "$CONFIG_FILE"
例如,如果您选择 8888 作为 $1,这将在您的配置文件中将 port= 更改为 port=8888。
【讨论】:
假设您的配置文件格式如下:
CONFIG_NUM=4
CONFIG_NUM2=5
CONFIG_DEBUG=n
在您的 bash 脚本中,您可以使用:
CONFIG_FILE=your_config_file
. $CONFIG_FILE
if [ $CONFIG_DEBUG == "y" ]; then
......
else
......
fi
$CONFIG_NUM、$CONFIG_NUM2、$CONFIG_DEBUG 是您所需要的。
读取值后,将其写回很容易:
echo "CONFIG_DEBUG=y" >> $CONFIG_FILE
【讨论】: