Ersetzen Sie alle Vorkommen eines Zeichens, wenn es vor einem anderen Zeichen vorkommt.

Ersetzen Sie alle Vorkommen eines Zeichens, wenn es vor einem anderen Zeichen vorkommt.

Ich muss in der Lage sein, einige Variablen aus einer Datei zu exportieren, damit ich sie in meinem BASH-Skript verwenden kann. Der Dateiinhalt sieht ungefähr so ​​aus:

my.variable.var1=a-long-ling.with.lot_of_different:characters:and_numbers
my.variable.another.var2=another-long-ling.with.lot_of_different:characters:and_numbers
my.variable.number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

Zuerst habe ich versucht, die Quelle sourceso zu verwenden, wie sie ist, und habe die folgende Fehlermeldung erhalten: command not found. Ich habe versucht, zu verwenden export, was zu der folgenden Fehlermeldung führte: not a valid identifier.

Ich glaube, ich kann nur exportieren, wenn ich meine Variable von my.variable.var1in ändere my_variable_var1.
Dies gelingt mir, indem ich die Zeile bei abschneide =und dann alle .s durch _s ersetze und die Variablen anschließend wieder hinzufüge.

Meine Frage ist also, ob es möglich ist, Folgendes zu ändern:

my.variable.var1=a-long-ling.with.lot_of_different:characters:and_numbers
my.variable.another.var2=another-long-ling.with.lot_of_different:characters:and_numbers
my.variable.number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

Zu

my_variable_var1=a-long-ling.with.lot_of_different:characters:and_numbers
my_variable_another_var2=another-long-ling.with.lot_of_different:characters:and_numbers
my_variable_number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

einen dieser coolen „Einzeiler“ verwenden? Würde ich gerne verwenden und außerdem viel lernen.

Antwort1

Mit sed:

sed -e :1 -e 's/^\([^=]*\)\./\1_/;t1'

Das heißt, ersetzen Sie eine andere Zeichenfolge als .die am Zeilenanfang, gefolgt von , .durch dieselbe Zeichenfolge und _, und wiederholen Sie den Vorgang, bis keine Übereinstimmung mehr vorliegt.

Mit awk:

awk -F = -v OFS== '{gsub(/\./, "_", $1); print}'

Falls die rechte Seite nun =für die Shell spezielle Zeichen enthält ( \"$&();'#~<>...`, Leerzeichen, Tabulator, andere Leerzeichen...), können Sie diese in Anführungszeichen setzen:

sed "s/'/'\\\\''/g;:1"'
     s/^\([^=]*\)\./\1_/;t1'"
     s/=/='/;s/\$/'/"

Oder:

awk -F = -v q="'" -v OFS== '
   {gsub(q, q "\\" q q)
    gsub(/\./, "_", $1)
    $2 = q $2
    print $0 q}'

Antwort2

Verwendung von bash:

while IFS='=' read -r i j; do echo "${i//./_}=$j" ; done

Wir haben das Parametererweiterungsmuster verwendet, ${i//./_}um alle .s _im Variablennamen durch s zu ersetzen.

Beispiel:

$ cat file.txt 
my.variable.var1=a-long-ling.with.lot_of_different:characters:and_numbers
my.variable.another.var2=another-long-ling.with.lot_of_different:characters:and_numbers
my.variable.number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

$ while IFS='=' read -r i j; do echo "${i//./_}=$j" ; done <file.txt 
my_variable_var1=a-long-ling.with.lot_of_different:characters:and_numbers
my_variable_another_var2=another-long-ling.with.lot_of_different:characters:and_numbers
my_variable_number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

Antwort3

Hier ist ein anderes sed:

sed 'h;s/\./_/g;G;s/=.*=/=/'

Dieses hier macht nur zwei Ersetzungen, unabhängig von der Anzahl der Punkte vor dem =„soh“, mit einer Eingabe wie:

my.var.an.other.var.with.many.dots=line.with.many:chars:and_numbers.and.stuff

Das Ergebnis ist

my_var_an_other_var_with_many_dots=line.with.many:chars:and_numbers.and.stuff

Dies funktioniert einwandfrei, wenn =pro Zeile ein Zeichen vorhanden ist (wie in Ihrer Beispieleingabe).
Ein allgemeinerer Ansatz, der immer nur bis zum ersten ersetzt =(und nur, wenn die Zeile mindestens ein Zeichen enthält =), selbst wenn mehrere Zeichen pro Zeile vorhanden sind =:

sed '/=/{                   # if line matches =
h                           # copy pattern space over the hold space
s/\./_/g                    # replace all . with =
G                           # append hold space content to pattern space
s/=.*\n[^=]*=/=/            # replace from the first = up to the first = after
}'                          # the newline character with a single =

oder

sed -e '/=/{h;s/\./_/g;G;s/=.*\n[^=]*=/=/' -e '}'

also mit einer Eingabe wie:

my.var.with.many.dots.but.no.equal.sign.and.stuff
my.var.with.many.dots=line.with.many:chars:numbers_and.stuff
other.var.with.many.dots=and.with.more.than=one.equal.sign=and.stuff

es gibt aus:

my.var.with.many.dots.but.no.equal.sign.and.stuff
my_var_with_many_dots=line.with.many:chars:numbers_and.stuff
other_var_with_many_dots=and.with.more.than=one.equal.sign=and.stuff

verwandte Informationen