Как использовать 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
Ответы
Ответ 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