【问题标题】:Modify config file using bash script使用 bash 脚本修改配置文件
【发布时间】:2010-03-17 18:18:26
【问题描述】:

我正在编写一个 bash 脚本来修改一个包含一堆键/值对的配置文件。如何读取密钥并找到值并可能对其进行修改?

【问题讨论】:

标签: bash configuration-files


【解决方案1】:

暗中修改单个值:

sed -c -i "s/\($TARGET_KEY *= *\).*/\1$REPLACEMENT_VALUE/" $CONFIG_FILE

假设目标键和替换值不包含任何特殊的正则表达式字符,并且您的键值分隔符是“=”。请注意,-c 选项取决于系统,您可能需要省略它才能执行 sed。

有关如何进行类似替换的其他提示(例如,当 REPLACEMENT_VALUE 中包含“/”字符时),there are some great examples here

【讨论】:

  • -c 在我的环境中似乎无效。当我摆脱-c时,它起作用了。谢谢。
  • 这个答案我真的得到了两次反对吗?我不仅设法猜到了 OP 想要什么,而且它简短而高效。有人愿意解释吗?
  • @prolink: ssh [opts] [user@]hostname command 将登录然后运行给定的命令。如果命令足够复杂,您可能希望将其存储在远程脚本中,这样您就可以运行ssh <host> path/to/script
  • 如果有人在 Mac 环境中执行它,您可能需要删除 -c 并在 -i 后添加 ''。就像sed -i '' "s...." $CONFIG_FILE
  • 非常有用的脚本。如果您的所有键都从行首开始,请考虑在$TARGET_KEY 之前添加^,否则如果您有两个键,例如even=2noteven=1,您最终会同时更改两者。
【解决方案2】:

希望这对某人有所帮助。我创建了一个独立的脚本,它需要各种配置处理。

#!/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

【讨论】:

  • 我怀疑这是否适用于 TOML,甚至 YAML 或 JSON,因为它们有部分。它只适用于键值对
【解决方案3】:

假设您有一个 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?)"

【讨论】:

    【解决方案4】:
    sed "/^$old/s/\(.[^=]*\)\([ \t]*=[ \t]*\)\(.[^=]*\)/\1\2$replace/" configfile
    

    【讨论】:

      【解决方案5】:

      所以我不能对此表示赞赏,因为它结合了 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

      但是,如果值有 / 字符,它会中断

      【讨论】:

        【解决方案6】:

        一般来说,使用 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恢复。)
        【解决方案7】:

        我已经这样做了:

        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

        【讨论】:

          【解决方案8】:

          假设您的配置文件格式如下:

          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
          

          【讨论】:

          • 这不会替换该值,只需在底部再次添加它,它完全依赖于配置文件是一个有效的 bash 脚本,而且......哇,如果里面有恶意怎么办配置文件?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-10-18
          • 2019-05-08
          • 1970-01-01
          • 1970-01-01
          • 2014-08-01
          • 1970-01-01
          • 2013-07-21
          相关资源
          最近更新 更多