如何使用 sed 更改我的配置文件,并具有灵活的键和值?

问题描述 投票:0回答:9

我想在配置文件中搜索以下表达式:“central.database”。 然后我想将与“central.database”关联的设置更改为“SQLTEST”。

配置文件的布局最初看起来像这样:

central.database = SQLFIRSTTEST

这就是我希望 sed 替换后的样子:

central.database = SQLTEST

我正在 bash 脚本中执行此操作,欢迎任何建议、建议或替代解决方案!

(实际上

central.database
SQLTEST
都来自这里的bash变量。)


我当前的代码(第三次尝试):

sshRetValue=$(ssh -p "35903" -i $HOME/sshids/idrsa-1.old ${1} <<EOF
        sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt;
        echo $?
EOF
)

错误信息:

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
linux bash sed
9个回答
121
投票
sed -i -e '/central\.database =/ s/= .*/= new_value/' /path/to/file

说明:

  • -i
    告诉 sed 将结果保存到输入文件中。如果没有它,sed 会将结果打印到标准输出。
  • /central\.database =/
    匹配包含斜杠之间的字符串的行:
    central.database =
    .
    被转义,因为它是正则表达式中的特殊字符。
  • s/OLD/NEW/
    部分执行 s 替换。 OLD 字符串是要匹配的正则表达式,
    NEW
    部分是要替换的字符串。
  • 在正则表达式中,
    .*
    表示“匹配任何内容”。因此
    = .*
    匹配等号、空格,然后匹配其他任何内容。

75
投票

这是一个示例表达式:

sed -i 's/^\(central\.database\s*=\s*\).*$/\1SQLTEST/' file.cfg

如果你想匹配其中包含

/
的内容,你可以使用另一个分隔符:

sed -i 's#^\(cent/ral\.data/base\s*=\s*\).*$#\1SQL/TEST#' file.cfg

或者使用变量扩展:

VAL="SQLTEST"
sed -i "s/^\(central\.database\s*=\s*\).*\$/\1$VAL/" file.cfg

在您的示例中:

sshRetValue=`sed -i "s/^\(\1$CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt`;

$CENTRAL_DB_NAME 之前有一个无效的。另外,sed 不打印它的返回值。这是检查返回值的首选方法:

sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt;
sed_return_value=$?

最终通过管道连接到 ssh(未测试):

sed_return_value=$(ssh server <<EOF
    sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt;
    echo $?
EOF
)

-i 用于替换输入文件中的数据。否则 sed 写入标准输出。

正则表达式有其自己的领域。在 stackoverflow 的答案中不可能深入解释它们,除非有一些特定的函数让你无法理解。


10
投票

我知道现在添加这个问题的答案已经太晚了,但是我想与大家分享我的知识。我遵循一种非常通用的方法来解决类似的问题。我已删除与字符串匹配的整行并将所需的值添加到该键。你的问题在这里有答案

replaceValue=SQLTEST
sed -i "/central.database =/d" /home/testing.txt
echo "central.database = $replaceValue"  >> /home/testing.txt

sed 从文件中删除匹配的字符串行,紧接着的下一行将所需的键和值插入到文件中。


5
投票

我喜欢使用

awk
来实现这一点,因为它很容易理解它在做什么,并且很好地处理分隔符(
=
),而且它必须针对未注释的行进行:

awk -v var="my_var" -v new_val="NEW VALUE" \  # set the vars
    'BEGIN{FS=OFS="="}                        # set separator to =
     match($1, "^\\s*" var "\\s*") {          # check if it matches
         $2=" " new_val                       # if so, replace the line
     }1' conf_file                            # print all lines

这使用

match()
来检查该模式是否出现在任何给定的行中。如果是,则用给定值执行替换。

例如:

$ cat conf
hello
my_var= SOME VALUE
#my_var = ANOTHER VALUE
bye

让我们将

my_var
中的值更改为
NEW VALUE
:

$ awk -v var="my_var" -v new_val="NEW VALUE" 'BEGIN{FS=OFS="="}match($1, "^\\s*" var "\\s*") {$2=" " new_val}1' conf
hello
my_var= NEW VALUE
#my_var = ANOTHER VALUE
bye

也可以在 shell 变量中设置值,然后将它们与

-v
:

一起使用
$ var="my_var"
$ new_value="NEW VALUE"
$ awk -v var="$var" -v new_val="$new_value" 'BEGIN{FS=OFS="="}match($1, "^\\s*" var "\\s*") {$2=" " new_val}1' conf

当然,您可以将所有这些放入 shell 函数中,然后正常调用:

#!/bin/bash

replace () {
   file=$1
   var=$2
   new_value=$3
   awk -v var="$var" -v new_val="$new_value" 'BEGIN{FS=OFS="="}match($1, "^\\s*" var "\\s*") {$2=" " new_val}1' "$file"
}

# Call the replace() function with the necessary parameters
replace "conf" "my_var" "NEW VALUE" 

执行后,返回

hello
my_var= NEW VALUE
#my_var = ANOTHER VALUE
bye

您也可以让脚本以如下方式接收参数:

./script.sh "conf_file" "var_to_replace" "NEW VALUE"
,然后将它们传递给函数。


2
投票

如果您想在 2 个属性文件之间进行替换,可以使用以下命令:

awk -F= 'NR==FNR{A[$1]=$2;next}$1 in A{$2=A[$1]}1' OFS='\=' /tmp/masterfile /opt/props/finalfile.properties > /tmp/tmp.txt && mv -f /tmp/tmp.txt /opt/props/finalfile.properties

2
投票

我有一个名为“config.php”的文件,我想更改其定义行之一。

例如,该行:

define('SOME_CONSTANT', 'old_value');

必须换成这个:

define('SOME_CONSTANT', 'new_value');

所以我就这么做了:

sed -i -e "/.*SOME_CONSTANT*./ s/.*/define('SOME_CONSTANT', 'new_value');/" path/to/config.php

在第一部分中,我正在寻找包含“SOME_CONSTANT”的行(因此是通配符)

然后我用新的定义替换该行,例如:define('SOME_CONSTANT', 'new_value');

在 Centos 7 中测试并运行良好


1
投票

工作示例

假设我们想要更新 Postgres 配置文件以增加连接数。

我们想在

/var/lib/postgresql/data/postgresql.conf
中更新这一行:

max_connections = 100

使用 sed:

sed -i 's/max_connections = 100/max_connections = 250/g' /var/lib/postgresql/data/postgresql.conf

这在更新 Docker 配置文件时非常有用,因为任何更新都需要自动化。


0
投票

我使用这个脚本来保持优先级..

论据 $1 将具有包含多个配置文件的文件夹。 $2 将具有需要在 $1 路径和子路径文件中替换的属性 #3 将具有需要在 $2 之上覆盖的属性

它还有隐藏逻辑来检查 $2 和 $3 中存在的键是否存在环境变量,并优先考虑它。

即如果环境中存在具有最高优先级的密钥。接下来是 3 美元,再接下来是 1 美元文件。

#!/bin/bash
#Usage is propertyReplacer <CONFIG_FOLDER_PATH> <CONFIG_FILE_2ND_PRIORITY> <CONFIG_FILE_1ST_PRIORITY>
function propertyReplacer() {

  filePathToAct="$1"
  propertiesFilePath="$2"
  propertiesSecureFilePath="$3"

  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 

} 

0
投票

我们如何使用 SED 命令将 #listen_addresses='localhost' 编辑为 listen_addresses='*'...?

© www.soinside.com 2019 - 2024. All rights reserved.