arquivo csv e awk: altere a entrada da segunda coluna se a primeira coluna corresponder, imprima o arquivo completo depois

arquivo csv e awk: altere a entrada da segunda coluna se a primeira coluna corresponder, imprima o arquivo completo depois

Estou escrevendo meu próprio gerenciador de senhas, que desejo ser estritamente compatível com POSIX. Para simplificar: eu tenho este arquivo file.csv:

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

Basicamente, quero ter uma função que receba dois argumentos: ela deve selecionar o primeiro argumento da primeira coluna e, a partir dessa linha, substituir a entrada da segunda coluna pelo segundo argumento.

Por exemplo: f "bla" "etewtw"alteraria a senha da última entrada para etewtw.

Tentei usar o awk, que também funciona:

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

Basicamente, tentei definir a segunda coluna para o newpwargumento se a primeira coluna corresponder ao accargumento. Após alterar o stream, quero imprimir o stream completo, o que não funciona. Obviamente, o que foi dito acima não é a solução correta, mas não sei como consertar isso.

A saída é:

bla;etewtw
posteo;tewtasdwqrr

Então deu certo, a entrada foi alterada (pelo menos no stream, mas na verdade alterar o arquivo não é difícil).

No entanto, surgem dois problemas:

  1. Faltam entradas na saída. Ou seja, mastodon;password2e test;test. Espero que a) permaneçam na mesma linha eb) permaneçam inalterados.

  2. Se eu quiser alterar a última linha, sempre está errado. Por exemplo, se eu usar awk -F ";" -v acc="posteo" -v newpw="test" '$1 ~ acc { $2=newpw; print $1";"$2 } END {print;} ', o resultado será:

posteo;test
posteo test

que não é o que eu quero. Quero que a última linha não seja diferente de qualquer outra linha.

Responder1

Você precisa de um destes itens para que seu nome e senha sejam tratados como strings literais:

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

Você precisa dessa abordagem porque as variáveis ​​​​passadas com -vsequências de escape expandidas. Portanto, se alguma das variáveis ​​que você passar contiver uma barra invertida, por exemplo foo\tbar, então o \tno meio será expandido e tratado como um caractere de tabulação literal.

Verhttp://cfajohnson.com/shell/cus-faq-2.html#Q24e/ouhttps://stackoverflow.com/questions/19075671/how-do-i-use-shell-variables-in-an-awk-scriptPara maiores informações.

Responder2

A única modificação que considero necessária é que você tenha uma printinstrução na ENDseção, mas falte uma para linhas não correspondentes. O que você deve fazer é

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

ou seja, simplesmente substitua o campo Nr. 2 com a nova senha e, em geral, imprima a linha (possivelmente modificada) (a notação abreviada para isso é 1). Com isso, também consegui alterar o registro da última linha.

Além disso, seria sensato tornar sua condição uma correspondência exata em vez de uma regex. Você nunca sabe se um nome de conta pode conter uma string que corresponda a outro nome de conta (como em admine webadmin, por exemplo).

informação relacionada