Подтвердить что ты не робот

Как использовать sed для изменения моих файлов конфигурации с помощью гибких ключей и значений?

Я хочу найти файл конфигурации для этого выражения: "central.database". Затем я хочу изменить параметр, связанный с "central.database", на "SQLTEST".

Схема конфигурационного файла будет выглядеть так:

central.database = SQLFIRSTTEST

Это то, что я хочу, чтобы оно выглядело после замены sed:

central.database = SQLTEST

Я делаю это в bash script, любые предложения, рекомендации или альтернативные решения приветствуются!

(На самом деле оба 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
4b9b3361

Ответ 1

Вот пример выражения:

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`;

Там a\1 до $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 пишет в stdout.

Регулярные выражения являются полем. Невозможно объяснить их в глубину в ответе stackoverflow, если только не существует определенной функции, которая ускользает от вас.

Ответ 2

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

Пояснение:

  • -i сообщает sed, чтобы сохранить результаты во входном файле. Без этого sed будет выводить результаты на стандартный вывод.
  • /central.database =/ соответствует строкам, содержащим строку между слэшами, т.е. "central.database =".
  • Часть s/OLD/NEW/ выполняет s ubstitution. Строка OLD является регулярным выражением для соответствия, а часть NEW - это строка для замены.
  • В регулярных выражениях .* означает "соответствовать всем". Таким образом, = .* соответствует знаку равенства, пробелу и затем всем остальным.

Ответ 3

Я знаю, что уже слишком поздно, чтобы добавить ответ на этот вопрос, однако я решил поделиться своими знаниями со всеми вами. Существует очень общий подход, которому я следовал, чтобы решить подобную проблему. Я удалил всю строку, которая соответствует строке, и добавил необходимые значения к этому ключу. На ваш вопрос вот ответ

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

sed удаляет совпадающую строку строки из файла, а следующая строка вставляет требуемый ключ и значение в файл.

Ответ 4

Мне нравится использовать 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 получать параметры таким образом, как: ./script.sh "conf_file" "var_to_replace" "NEW VALUE", а затем передать их функции.

Ответ 5

Если вы хотите заменить два файла свойств, вы можете использовать это:

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

Ответ 6

Я использовал этот script для сохранения приоритетов.

Аргументы $1 будет иметь папку, в которой есть несколько файлов конфигурации. $2 будет иметь свойства, которые необходимо заменить в файлах пути и подпунктов $1 # 3 будут иметь свойства, которые необходимо переопределить поверх $2

Он также имеет скрытую логику для проверки наличия переменных среды для ключей, существующих в $2 и $3, и отдавать приоритет этому.

i.e Если в среде существует ключ, который будет иметь наивысший приоритет. Рядом с этим будет $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 

} 

Ответ 7

У меня есть файл с именем "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