it-swarm.com.de

Wie verwende ich sed zum Ändern meiner Konfigurationsdateien mit flexiblen Schlüsseln und Werten?

Ich möchte eine Konfigurationsdatei nach diesem Ausdruck durchsuchen: "central.database" . Ich möchte dann die mit "central.database" verknüpfte Einstellung in "SQLTEST" ändern.

Das Layout der Konfigurationsdatei würde zunächst so aussehen:

central.database = SQLFIRSTTEST

Ich möchte, dass es nach dem Sed-Ersatz so aussieht:

central.database = SQLTEST

Ich mache das in einem Bash-Skript, alle Vorschläge, Empfehlungen oder Alternativlösungen sind willkommen!

(Tatsächlich stammen central.database und SQLTEST hier von bash-Variablen.)


Mein aktueller Code (dritter Versuch):

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
)

Fehlermeldung:

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

Hier ist ein Beispielausdruck:

sed -i 's/^\(central\.database\s*=\s*\).*$/\1SQLTEST/' file.cfg

Wenn Sie Sachen mit / darin abgleichen möchten, können Sie ein anderes Trennzeichen verwenden:

sed -i 's#^\(cent/ral\.data/base\s*=\s*\).*$#\1SQL/TEST#' file.cfg

Oder mit variabler Erweiterung:

VAL="SQLTEST"
sed -i "s/^\(central\.database\s*=\s*\).*\$/\1$VAL/" file.cfg

In deinem Beispiel: 

sshRetValue=`sed -i "s/^\(\1$CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt`;

Vor $ CENTRAL_DB_NAME ist ein\1 ungültig. Sed druckt auch nicht den Rückgabewert. Dies ist die bevorzugte Methode zum Überprüfen von Rückgabewerten:

sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt;
sed_return_value=$?

Und letztendlich Piping zu ssh (nicht getestet):

sed_return_value=$(ssh server <<EOF
    sed -i "s/^\($CENTRAL_DB_NAME\s*=\s*\).*\$/\1$CENTRAL_DB_VALUE/" /home/testing.txt;
    echo $?
EOF
)

Das -i dient zum Ersetzen von Daten in der Eingabedatei. Ansonsten schreibt sed zu stdout.

Reguläre Ausdrücke sind ein Feld für sich. Es wäre unmöglich, sie in einer stackoverflow-Antwort ausführlich zu erklären, es sei denn, es gibt eine bestimmte Funktion, die Ihnen entgeht.

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

Erläuterung:

  • -i weist sed an, die Ergebnisse in der Eingabedatei zu speichern. Andernfalls werden die Ergebnisse in sed gedruckt.
  • /central.database =/ vergleicht Zeilen, die die Zeichenfolge zwischen Schrägstrichen enthalten, d. h. "central.database =".
  • Der s/OLD/NEW/-Teil führt a aus substitution. Die OLD-Zeichenfolge ist ein regulärer Ausdruck, der abgeglichen werden soll, und der NEW-Teil ist die zu ersetzende Zeichenfolge.
  • In regulären Ausdrücken bedeutet .* "Übereinstimmung". = .* stimmt also mit einem Gleichheitszeichen, einem Leerzeichen und danach mit irgendetwas anderem überein.
79
John Kugelman

Ich weiß, es ist zu spät, um eine Antwort auf diese Frage hinzuzufügen, aber ich dachte, mein Wissen an Sie alle weiterzugeben. Es gibt einen sehr allgemeinen Ansatz, dem ich gefolgt bin, um ein ähnliches Problem zu lösen. Ich habe die gesamte Zeile gelöscht, die mit der Zeichenfolge übereinstimmt, und die erforderlichen Werte zu diesem Schlüssel hinzugefügt. Auf deine Frage hier ist die Antwort

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

sed löscht die übereinstimmende Zeichenfolgezeile aus der Datei und die nächste Zeile fügt den erforderlichen Schlüssel und Wert in die Datei ein.

Ich benutze gerne awk, da es leicht zu verstehen ist, was es tut und sich sehr gut um das Trennzeichen (=) kümmert und auch die Tatsache, dass es sich um eine unkommentierte Zeile handeln muss:

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

Dies verwendet match() , um zu prüfen, ob das Muster in einer bestimmten Zeile vorkommt. Wenn dies der Fall ist, führt es den Ersatz mit dem angegebenen Wert aus.

Zum Beispiel:

$ cat conf
hello
my_var= SOME VALUE
#my_var = ANOTHER VALUE
bye

Ändern wir den Wert in my_var in 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

Es ist auch möglich, die Werte in Shell-Variablen festzulegen und sie dann mit -v zu verwenden:

$ 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

Natürlich können Sie all dies in eine Shell-Funktion eingeben, die Sie dann normal aufrufen:

#!/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" 

Bei der Ausführung kehrt dies zurück

hello
my_var= NEW VALUE
#my_var = ANOTHER VALUE
bye

Während Sie das Skript auch dazu bringen können, die Parameter auf eine Weise zu empfangen, geben Sie Folgendes ein: ./script.sh "conf_file" "var_to_replace" "NEW VALUE", um sie dann an die Funktion zu übergeben.

4
fedorqui

Wenn Sie zwischen zwei Eigenschaftsdateien ersetzen möchten, können Sie Folgendes verwenden: 

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

Ich habe dieses Skript benutzt, um die Prioritäten zu halten.

Die Argumente $ 1 hat einen Ordner, in dem sich mehrere Konfigurationsdateien befinden. $ 2 hat Eigenschaften, die in $ 1 Pfad- und Unterpfaddateien .__ ersetzt werden müssen. # 3 wird Eigenschaften haben, die zusätzlich zu $ ​​2 außer Kraft gesetzt werden müssen

Es hat auch eine versteckte Logik, um das Vorhandensein von Umgebungsvariablen für die in $ 2 und $ 3 vorhandenen Schlüssel zu überprüfen und diesem Vorrang zu geben.

wenn also ein Schlüssel in einer Umgebung vorhanden ist, der höchste Priorität hätte. Daneben wären $ 3 und daneben $ 1 Dateien.

#!/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