Comment puis-je utiliser sed pour modifier mes fichiers de configuration, avec des clés et des valeurs?
Je veux rechercher dans un fichier de configuration cette expression: "central.base de données". Je veux ensuite changer le paramètre associé à " central.base de données" à "SQLTEST".
La disposition du fichier de configuration ressemblerait initialement à ceci:
central.database = SQLFIRSTTEST
C'est ce que je veux qu'il ressemble après le remplacement de sed:
central.database = SQLTEST
Je le fais dans un script bash, toutes les suggestions, recommandations ou solutions alternatives sont les bienvenues!
(en Fait les deux central.database
et SQLTEST
venir de variables bash ici.)
Mon code actuel (troisième tentative):
sshRetValue=$(ssh -p "35903" -i $HOME/sshids/idrsa-1.old ${1} <<EOF
sed -i "s/^($CENTRAL_DB_NAMEs*=s*).*$/1$CENTRAL_DB_VALUE/" /home/testing.txt;
echo $?
EOF
)
Message d'Erreur:
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
6 réponses
Voici un exemple d'expression:
sed -i 's/^\(central\.database\s*=\s*\).*$/\1SQLTEST/' file.cfg
Si vous souhaitez obtenir des trucs avec /
, vous pouvez utiliser un autre délimiteur:
sed -i 's#^\(cent/ral\.data/base\s*=\s*\).*$#\1SQL/TEST#' file.cfg
Ou avec expansion variable:
VAL="SQLTEST"
sed -i "s/^\(central\.database\s*=\s*\).*\$/\1$VAL/" file.cfg
Dans votre exemple:
sshRetValue=`sed -i "s/^\(\1$CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt`;
Il y a un \1 avant $CENTRAL_DB_NAME qui n'est pas valide. En outre, sed n'imprime pas sa valeur de retour. C'est le moyen préféré de vérifier les valeurs de retour:
sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt;
sed_return_value=$?
Et finalement tuyauterie à ssh (non testé):
sed_return_value=$(ssh server <<EOF
sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt;
echo $?
EOF
)
Le-i est pour remplacer les données dans l'entrée fichier. Sinon, sed écrit sur stdout.
Les expressions régulières sont un champ qui leur est propre. Il serait impossible de les expliquer en profondeur dans une réponse stackoverflow, à moins qu'il n'y ait une fonction spécifique qui vous échappe.
sed -i -e '/central.database =/ s/= .*/= new_value/' /path/to/file
Explication:
-
-i
indique à sed pour enregistrer les résultats dans le fichier d'entrée. Sans cela, sed imprimera les résultats sur stdout. -
/central.database =/
correspond aux lignes qui contiennent la chaîne entre les barres obliques, c'est-à-dire "central.base de données =". - la partie
s/OLD/NEW/
effectue une ubstitution s. L'ancienne chaîne est une expression régulière à faire correspondre et la partieNEW
est la chaîne à remplacer. - dans les expressions régulières,
.*
signifie "correspondre à n'importe quoi". Donc= .*
correspond un signe égal, l'espace, et puis toute autre chose par la suite.
J'aime utiliser awk
pour cela, car il est assez facile de comprendre ce qu'il fait et prend très bien soin du séparateur (=
) et aussi du fait qu'il doit être fait à une ligne non commentée:
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
Il utilise match()
pour vérifier si le motif se produit dans une ligne donnée. Si c'est le cas, il effectue le remplacement avec la valeur donnée.
Par exemple:
$ cat conf
hello
my_var= SOME VALUE
#my_var = ANOTHER VALUE
bye
Nous allons modifier la valeur dans 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
Il est également possible de définissez les valeurs dans les variables shell, puis utilisez-les avec -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
Et vous pouvez bien sûr mettre tout cela dans une fonction shell que vous appelez normalement:
#!/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"
Lors de l'exécution, cela renvoie
hello
my_var= NEW VALUE
#my_var = ANOTHER VALUE
bye
Alors que vous pouvez également faire en sorte que le script reçoive les paramètres d'une manière comme: ./script.sh "conf_file" "var_to_replace" "NEW VALUE"
pour ensuite les transmettre à la fonction.
Je sais qu'il est trop tard pour ajouter une réponse à cette question cependant, j'ai pensé à partager mes connaissances avec vous tous. Il y a une approche très générale que j'ai suivie pour résoudre un problème similaire. J'ai supprimé toute la ligne qui correspond à la chaîne et ajouté les valeurs requises à cette clé. À votre question, voici la réponse
replaceValue=SQLTEST
sed -i "/central.database =/d" /home/testing.txt
echo "central.database = $replaceValue" >> /home/testing.txt
Sed supprime la ligne de chaîne correspondante du fichier et la ligne suivante immédiate insère la clé et la valeur requises dans le fichier. fichier.
Si vous souhaitez remplacer entre 2 fichiers de propriétés vous pouvez utiliser ceci:
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
J'ai utilisé ce script pour garder les priorités..
Les arguments $1 dossier dans lequel plusieurs fichiers de configuration existent. $2 aura des propriétés qui doivent être remplacées dans les fichiers $1 path et sub paths #3 aura des propriétés qui doivent être remplacées par $2
Il a également une logique cachée pour vérifier l'existence de variables d'environnement pour les clés existent dans $2 et $3 et donner la priorité à cela.
C'est-à-dire si une clé existe dans un environnement qui serait la plus élevée priorité. À côté de cela $3 et à côté de cela $ 1 Fichier.
#!/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
}