Linux 如何使用 sed 更改我的配置文件,具有灵活的键和值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5955548/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I use sed to change my configuration files, with flexible keys and values?
提问by prolink007
I want to search a configuration file for this expression: "central.database". I then want to change the setting associated with "central.database" to "SQLTEST".
我想搜索这个表达式的配置文件:“central.database”。然后我想将与“central.database”关联的设置更改为“SQLTEST”。
The layout of the config file would look like this initially:
配置文件的布局最初如下所示:
central.database = SQLFIRSTTEST
This is what i want it to look like after the sed replacement:
这就是我希望它在 sed 替换后的样子:
central.database = SQLTEST
I am doing this in a bash script, any suggestions, recommendations or alternative solutions are welcome!
我在 bash 脚本中执行此操作,欢迎提供任何建议、建议或替代解决方案!
(Actually both central.database
and SQLTEST
come from bash variables here.)
(实际上,这两个central.database
和SQLTEST
来自bash的变量在这里。)
My current code (third attempt):
我当前的代码(第三次尝试):
sshRetValue=$(ssh -p "35903" -i $HOME/sshids/idrsa-1.old <<EOF
sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*$/$CENTRAL_DB_VALUE/" /home/testing.txt;
echo $?
EOF
)
Error message:
错误信息:
Pseudo-terminal will not be allocated because stdin is not a terminal.
sed: -e expression #1, char 58: unknown option to `s'
-bash: line 3: EOF: command not found
采纳答案by sapht
Here's an example expression:
这是一个示例表达式:
sed -i 's/^\(central\.database\s*=\s*\).*$/SQLTEST/' file.cfg
If you want to match stuff with /
in it, you can use another delimiter:
如果你想匹配里面的东西/
,你可以使用另一个分隔符:
sed -i 's#^\(cent/ral\.data/base\s*=\s*\).*$#SQL/TEST#' file.cfg
Or with variable expansion:
或者使用变量扩展:
VAL="SQLTEST"
sed -i "s/^\(central\.database\s*=\s*\).*$/$VAL/" file.cfg
In your example:
在你的例子中:
sshRetValue=`sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*$/$CENTRAL_DB_VALUE/" /home/testing.txt`;
There's a \1 before $CENTRAL_DB_NAME that's invalid. Also, sed doesn't print it's return value. This is the preferred way to check return values:
$CENTRAL_DB_NAME 之前有一个无效的 \1。此外, sed 不打印它的返回值。这是检查返回值的首选方法:
sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*$/$CENTRAL_DB_VALUE/" /home/testing.txt;
sed_return_value=$?
And ultimately piping to ssh (not tested):
并最终通过管道传输到 ssh(未测试):
sed_return_value=$(ssh server <<EOF
sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*$/$CENTRAL_DB_VALUE/" /home/testing.txt;
echo $?
EOF
)
The -i is for replacing data in the input file. Otherwise sed writes to stdout.
-i 用于替换输入文件中的数据。否则 sed 写入标准输出。
Regular expressions are a field of their own. It would be impossible to explain them in depth in a stackoverflow answer, unless there is some specific function that's eluding you.
正则表达式是它们自己的领域。在 stackoverflow 答案中不可能对它们进行深入解释,除非有一些特定的功能让你望而却步。
回答by John Kugelman
sed -i -e '/central\.database =/ s/= .*/= new_value/' /path/to/file
Explanation:
解释:
-i
tells sed to save the results to the input file. Without it sed will print the results to stdout./central\.database =/
matches lines that contain the string between slashes:central.database =
. The.
is escaped since it's a special character in regex.- The
s/OLD/NEW/
part performs a substitution. The OLD string is a regular expression to match and theNEW
part is the string to substitute in. - In regular expressions,
.*
means "match anything". So= .*
matches an equal sign, space, and then anything else afterward.
-i
告诉 sed 将结果保存到输入文件中。没有它 sed 会将结果打印到标准输出。/central\.database =/
匹配包含斜杠之间字符串的行:central.database =
。将.
被转义,因为它是在正则表达式特殊字符。- 的
s/OLD/NEW/
部分执行一个小号ubstitution。OLD 字符串是要匹配的正则表达式,NEW
部分是要替换的字符串。 - 在正则表达式中,
.*
表示“匹配任何内容”。So= .*
匹配等号、空格,然后匹配其他任何内容。
回答by user5433596
If you want to replace between 2 property files you can use this:
如果要在 2 个属性文件之间替换,可以使用以下命令:
awk -F= 'NR==FNR{A[]=;next} in A{=A[]}1' OFS='\=' /tmp/masterfile /opt/props/finalfile.properties > /tmp/tmp.txt && mv -f /tmp/tmp.txt /opt/props/finalfile.properties
回答by fedorqui 'SO stop harming'
I like using awk
for this, since it is quite easy to understand what it is doing and takes care very well of the separator (=
) and also the fact that it must be done to an uncommented line:
我喜欢使用awk
它,因为它很容易理解它在做什么,并且很好地处理了分隔符 ( =
) 以及它必须对未注释的行进行的事实:
awk -v var="my_var" -v new_val="NEW VALUE" \ # set the vars
'BEGIN{FS=OFS="="} # set separator to =
match(, "^\s*" var "\s*") { # check if it matches
=" " new_val # if so, replace the line
}1' conf_file # print all lines
This uses match()
to check if the pattern occurs in any given line. If it does, it performs the replacement with the given value.
这用于match()
检查模式是否出现在任何给定的行中。如果是,则使用给定值执行替换。
For example:
例如:
$ cat conf
hello
my_var= SOME VALUE
#my_var = ANOTHER VALUE
bye
Let's change the value in my_var
to NEW VALUE
:
让我们将值更改my_var
为NEW VALUE
:
$ awk -v var="my_var" -v new_val="NEW VALUE" 'BEGIN{FS=OFS="="}match(, "^\s*" var "\s*") {=" " new_val}1' conf
hello
my_var= NEW VALUE
#my_var = ANOTHER VALUE
bye
It is also possible to set the values in shell variables and then use them with -v
:
也可以在 shell 变量中设置值,然后将它们用于-v
:
$ var="my_var"
$ new_value="NEW VALUE"
$ awk -v var="$var" -v new_val="$new_value" 'BEGIN{FS=OFS="="}match(, "^\s*" var "\s*") {=" " new_val}1' conf
And you can of course put all of this within a shell function that you then call normally:
您当然可以将所有这些放在一个 shell 函数中,然后您可以正常调用该函数:
#!/bin/bash
replace () {
file=
var=
new_value=
awk -v var="$var" -v new_val="$new_value" 'BEGIN{FS=OFS="="}match(, "^\s*" var "\s*") {=" " new_val}1' "$file"
}
# Call the replace() function with the necessary parameters
replace "conf" "my_var" "NEW VALUE"
Upon execution, this returns
执行后,这将返回
hello
my_var= NEW VALUE
#my_var = ANOTHER VALUE
bye
While you can also make the script receive the parameters in a way like: ./script.sh "conf_file" "var_to_replace" "NEW VALUE"
to then pass them to the function.
虽然您也可以让脚本以如下方式接收参数:./script.sh "conf_file" "var_to_replace" "NEW VALUE"
然后将它们传递给函数。
回答by Venkateswara Rao
I used this script for keeping the priorities..
我用这个脚本来保持优先级..
The arguments $1 will have folder in which multiple config files exist. $2 will have properties which need to be replaced in $1 path and sub paths files #3 will have properties which need to be override on top of $2
参数 $1 将包含其中存在多个配置文件的文件夹。$2 将具有需要在 $1 路径和子路径文件中替换的属性 #3 将具有需要在 $2 之上覆盖的属性
It also has hidden logic to check for existence of environment variables for the keys exist in $2 and $3 and give priority to that.
它还有隐藏的逻辑来检查 $2 和 $3 中存在的键的环境变量是否存在并优先考虑。
i.e If a key exist in environment that would be highest priority. Next to that would $3 and next to that would $1 file.
即,如果密钥存在于最高优先级的环境中。旁边是 3 美元,旁边是 1 美元的文件。
#!/bin/bash
#Usage is propertyReplacer <CONFIG_FOLDER_PATH> <CONFIG_FILE_2ND_PRIORITY> <CONFIG_FILE_1ST_PRIORITY>
function propertyReplacer() {
filePathToAct=""
propertiesFilePath=""
propertiesSecureFilePath=""
declare -A keyValues
while IFS='=' read -r key value; do
if [ "$key" == "" ]; then
continue
elif [[ "$key" =~ ^#.*$ ]]; then
continue
else
echo $key " --> " $value
keyValues[$key]=$value
fi
done < "$propertiesFilePath"
if [ ! -f "$propertiesSecureFilePath" ]; then
continue
else
while IFS='=' read -r key value; do
if [ "$key" == "" ]; then
continue
elif [[ "$key" =~ ^#.*$ ]]; then
continue
else
echo $key " --> " $value
keyValues[$key]=$value
fi
done < "$propertiesSecureFilePath"
fi
for key in ${!keyValues[@]}; do
envProp=${key//[@]/}
if [ "$(eval echo '$'$envProp)" == "" ]; then
echo "Environment key not exist" $envProp
else
value=$(eval echo '$'$envProp)
echo "From Environment " $envProp " --> "$value
keyValues[$key]=$value
fi
done
find "$filePathToAct" | while read -r resultFileName; do
if [ ! -f "$resultFileName" ]; then
continue
else
echo "Acting on the file $resultFileName"
for key in ${!keyValues[@]}; do
value=$(echo "${keyValues[${key}]}" | sed 's/\//\\//g')
echo "sed -i 's/$key/$value/g' $resultFileName "
eval "sed -i 's/$key/$value/g' $resultFileName "
done
fi
done
}
回答by Alex Raj Kaliamoorthy
I know it is too late to add an answer to this question however, I thought to share my knowledge to you all. There is a very general approach which I have followed to solve a similar kind of problem. I have deleted the whole line which is matching the string and added the required values to that key. To your question here is the answer
我知道现在为这个问题添加答案为时已晚,但我想与大家分享我的知识。我遵循了一种非常通用的方法来解决类似的问题。我删除了与字符串匹配的整行,并将所需的值添加到该键。你的问题在这里是答案
replaceValue=SQLTEST
sed -i "/central.database =/d" /home/testing.txt
echo "central.database = $replaceValue" >> /home/testing.txt
sed deletes the matching string line from the file and the immediate next line is inserting the required key and value to the file.
sed 从文件中删除匹配的字符串行,紧接着的下一行将所需的键和值插入到文件中。
回答by Theo Orphanos
I have a file called "config.php" and I wanted to change one of its definitions lines.
我有一个名为“config.php”的文件,我想更改其定义行之一。
For example, the line:
例如,该行:
define('SOME_CONSTANT', 'old_value');
had to be replaced with this one:
必须用这个替换:
define('SOME_CONSTANT', 'new_value');
So I did that:
所以我这样做了:
sed -i -e "/.*SOME_CONSTANT*./ s/.*/define('SOME_CONSTANT', 'new_value');/" path/to/config.php
In the first part, I am looking for a line that contains "SOME_CONSTANT" (thus the wildcards)
在第一部分中,我正在寻找包含“SOME_CONSTANT”的行(因此是通配符)
Then I replace that line with a new definition such as: define('SOME_CONSTANT', 'new_value');
然后我用一个新定义替换该行,例如:define('SOME_CONSTANT', 'new_value');
Tested and works fine in Centos 7
在 Centos 7 中测试并正常工作