Ich schreibe meinen eigenen Passwort-Manager, der streng POSIX-kompatibel sein soll. Um es zu vereinfachen: Ich habe diese Datei file.csv
:
mastodon;password2
bla;test
test;test
posteo;tewtasdwqrr
Grundsätzlich möchte ich eine Funktion haben, die zwei Argumente annimmt: Sie soll das erste Argument aus der ersten Spalte auswählen und ab dieser Zeile den Eintrag in der zweiten Spalte durch das zweite Argument ersetzen.
Beispiel: f "bla" "etewtw"
würde das Passwort des letzten Eintrags in ändern etewtw
.
Ich habe versucht, awk zu verwenden, was auch einigermaßen funktioniert:
awk -F ";" -v acc="bla" -v newpw="etewtw" \
'$1 ~ acc { $2=newpw; print $1";"$2 } END {print;} ' file.csv
Im Grunde genommen habe ich versucht, die zweite Spalte auf das Argument zu setzen, newpw
wenn die erste Spalte mit dem acc
Argument übereinstimmt. Nach dem Ändern des Streams möchte ich den gesamten Stream drucken, was aber nicht funktioniert. Das Obige ist offensichtlich nicht die richtige Lösung, aber ich weiß nicht, wie ich das beheben kann.
Die Ausgabe ist:
bla;etewtw
posteo;tewtasdwqrr
Es ist also einigermaßen erfolgreich, der Eintrag wurde geändert (zumindest im Stream, aber eigentlich ist das Ändern der Datei nicht schwierig).
Es treten jedoch zwei Probleme auf:
In der Ausgabe fehlen Einträge. Nämlich
mastodon;password2
undtest;test
. Ich erwarte, dass diese a) in der gleichen Zeile bleiben und b) unverändert bleiben.Wenn ich die letzte Zeile ändern möchte, ist das immer falsch. Wenn ich
awk -F ";" -v acc="posteo" -v newpw="test" '$1 ~ acc { $2=newpw; print $1";"$2 } END {print;} '
stattdessen beispielsweise verwende, ist das Ergebnis:
posteo;test
posteo test
was ich nicht will. Ich will, dass die letzte Zeile sich nicht von den anderen unterscheidet.
Antwort1
Sie benötigen eine der folgenden Optionen, damit Ihr Name und Ihr Kennwort als Zeichenfolgen behandelt werden:
acc='bla' newpw='etewtw' awk '
BEGIN{FS=OFS=";"; acc=ENVIRON["acc"]; newpw=ENVIRON["newpw"]}
$1 == acc{$2=newpw} 1
' file.csv
awk '
BEGIN{FS=OFS=";"; acc=ARGV[1]; newpw=ARGV[2]; ARGV[1]=ARGV[2]=""}
$1 == acc{$2=newpw} 1
' 'bla' 'etewtw' file.csv
Sie benötigen diesen Ansatz, weil Variablen mit -v
Escape-Sequenzen für die Erweiterung übergeben werden. Wenn also eine der von Ihnen übergebenen Variablen einen Backslash enthält, z. B. foo\tbar
, wird das \t
in der Mitte erweitert und als wörtliches Tabulatorzeichen behandelt.
Sehenhttp://cfajohnson.com/shell/cus-faq-2.html#Q24und/oderhttps://stackoverflow.com/questions/19075671/wie-verwende-ich-shell-variable-in-einem-awk-scriptfür mehr Informationen.
Antwort2
Die einzige Änderung, die ich für notwendig halte, ist, dass Sie eine print
Anweisung im END
Abschnitt haben, aber eine für nicht übereinstimmende Zeilen fehlt. Was Sie stattdessen tun sollten, ist
awk -F';' -v OFS=';' -v acc='bla' -v newpw='etewtw' '$1 == acc {$2=newpw}1' file.csv
d.h. einfach Feld Nr. 2 durch das neue Passwort ersetzen, und generell die (ggf. geänderte) Zeile ausdrucken (die Kurzschreibweise dafür ist das 1
). Damit ist es mir auch gelungen, den Eintrag in der letzten Zeile zu ändern.
Darüber hinaus erscheint es sinnvoll, Ihre Bedingung als exakte Übereinstimmung statt als regulären Ausdruck festzulegen, da Sie nie wissen, ob ein Kontoname eine Zeichenfolge enthält, die mit einem anderen Kontonamen übereinstimmt (wie z. B. in „ admin
und“ webadmin
).