CSV-файл и awk: изменить запись во втором столбце, если первый столбец совпадает, затем вывести полный файл

CSV-файл и awk: изменить запись во втором столбце, если первый столбец совпадает, затем вывести полный файл

Я пишу свой собственный менеджер паролей, который я хочу строго соответствовать POSIX. Для упрощения: у меня есть этот файл, file.csv:

mastodon;password2
bla;test
test;test
posteo;tewtasdwqrr

По сути, мне нужна функция, которая принимает два аргумента: она должна выбрать первый аргумент из первого столбца и в этой строке заменить запись второго столбца вторым аргументом.

Например: f "bla" "etewtw"изменит пароль последней записи на etewtw.

Я попробовал использовать awk, что тоже работает:

awk -F ";" -v acc="bla" -v newpw="etewtw" \
'$1 ~ acc { $2=newpw; print $1";"$2 } END {print;} ' file.csv

В принципе, я пытался установить второй столбец в newpwаргумент, если первый столбец совпадает с accаргументом. После изменения потока я хочу вывести полный поток, что не работает. Вышеприведенное решение, очевидно, не является правильным, но я не знаю, как это исправить.

Вывод:

bla;etewtw
posteo;tewtasdwqrr

Так что это своего рода успех, запись была изменена (по крайней мере в потоке, но на самом деле изменить файл несложно).

Однако возникают две проблемы:

  1. В выводе отсутствуют записи. А именно mastodon;password2и test;test. Я ожидаю, что они а) останутся на той же строке и б) не изменятся.

  2. Если я хочу изменить последнюю строку, это всегда неправильно. Например, если я использую awk -F ";" -v acc="posteo" -v newpw="test" '$1 ~ acc { $2=newpw; print $1";"$2 } END {print;} 'вместо этого, результат будет:

posteo;test
posteo test

а это не то, чего я хочу. Я хочу, чтобы последняя строка не отличалась от любой другой строки.

решение1

Чтобы ваше имя и пароль рассматривались как буквальные строки, вам понадобится любой из этих вариантов:

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

Вам нужен этот подход, потому что переменные передаются с помощью -vescape-последовательностей expand. Таким образом, если любая из передаваемых вами переменных содержит обратную косую черту, например foo\tbar, то \tв середине будет расширен и обработан как буквальный символ табуляции.

Видетьhttp://cfajohnson.com/shell/cus-faq-2.html#Q24и/илиhttps://stackoverflow.com/questions/19075671/how-do-i-use-shell-variables-in-an-awk-scriptЧтобы получить больше информации.

решение2

Единственное изменение, которое я бы увидел необходимым, это то, что у вас есть оператор printв ENDразделе, но отсутствует один для несовпадающих строк. Вместо этого вам следует сделать следующее:

awk -F';' -v OFS=';' -v acc='bla' -v newpw='etewtw' '$1 == acc {$2=newpw}1' file.csv

т.е. просто замените поле № 2 новым паролем и в общем случае выведите (возможно, измененную) строку (сокращенное обозначение для этого — 1). С помощью этого мне также удалось изменить запись в последней строке.

Кроме того, было бы разумно сделать условие точным совпадением вместо регулярного выражения, поскольку никогда не знаешь, может ли одно имя учетной записи содержать строку, которая совпадает с другим именем учетной записи (например, как adminи webadmin).

Связанный контент