csv-Datei & awk: zweiten Spalteneintrag ändern, wenn erste Spalte übereinstimmt, anschließend komplette Datei drucken

csv-Datei & awk: zweiten Spalteneintrag ändern, wenn erste Spalte übereinstimmt, anschließend komplette Datei drucken

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, newpwwenn die erste Spalte mit dem accArgument ü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:

  1. In der Ausgabe fehlen Einträge. Nämlich mastodon;password2und test;test. Ich erwarte, dass diese a) in der gleichen Zeile bleiben und b) unverändert bleiben.

  2. 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 -vEscape-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 \tin 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 printAnweisung im ENDAbschnitt 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 „ adminund“ webadmin).

verwandte Informationen