web-dev-qa-db-ja.com

柔軟なキーと値を使用して、sedを使用して構成ファイルを変更するにはどうすればよいですか?

次の式の構成ファイルを検索したい:「central.database」。次に、「central.database」に関連付けられている設定を「SQLTEST」に変更します。

構成ファイルのレイアウトは、最初は次のようになります。

central.database = SQLFIRSTTEST

これは、sed交換後の外観です。

central.database = SQLTEST

これはbashスクリプトで行っています。提案、推奨事項、または代替ソリューションは歓迎します。

(実際には両方central.databaseおよびSQLTESTは、ここではbash変数から取得されます。


私の現在のコード(3回目の試行):

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
38
prolink007

式の例を次に示します。

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の前に無効な\ 1があります。また、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はstdoutに書き込みます。

正規表現は独自のフィールドです。あなたを避けている特定の機能がない限り、stackoverflowの答えでそれらを詳細に説明することは不可能でしょう。

57
sapht
sed -i -e '/central.database =/ s/= .*/= new_value/' /path/to/file

説明:

  • -iは、結果を入力ファイルに保存するようにsedに指示します。 sedを使用しないと、結果が標準出力に出力されます。
  • /central.database =/は、スラッシュの間に文字列を含む行、つまり「central.database = "」に一致します。
  • s/OLD/NEW/部分は sub責。 OLD文字列は一致する正規表現であり、NEW部分は置換する文字列です。
  • 正規表現では、.*は「すべてに一致」を意味します。そう = .*は、等号、スペース、およびその後のその他のものと一致します。
82
John Kugelman

この質問に答えを追加するのは遅すぎることを知っていますが、皆さんに私の知識を共有したいと思いました。同様の問題を解決するために私が従った非常に一般的なアプローチがあります。文字列に一致する行全体を削除し、そのキーに必要な値を追加しました。あなたの質問に対する答えはここにあります

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

sedは一致する文字列行をファイルから削除し、すぐ次の行が必要なキーと値をファイルに挿入します。

これには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
_

シェル変数に値を設定し、それらを_-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
_

もちろん、これらすべてをシェル関数内に配置して、通常どおり呼び出すことができます。

_#!/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"_を使用して関数に渡します。

4
fedorqui

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
user5433596

このスクリプトを使用して、優先順位を維持しました。

引数$ 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