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
31
demandé sur fedorqui 2011-05-10 23:41:30

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.

48
répondu sapht 2011-05-11 16:21:43
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 partie NEW 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.
77
répondu John Kugelman 2012-11-28 02:23:05

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.

4
répondu fedorqui 2016-08-29 13:09:41

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.

3
répondu Alex Raj Kaliamoorthy 2018-02-13 07:18:02

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
2
répondu user5433596 2015-10-11 15:29:58

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 

} 
0
répondu Venkateswara Rao 2017-11-27 11:12:59