
Eu tenho um conjunto de dados que contém informações de contato de alunos. O conjunto de dados de amostra é o seguinte
First Name, Last Name, Address, Phone Number
John, Doe, "House # 11, Street xyz, Road, Area",00000000
Sara, Taylor, "Jake Lake%, Apartment #22, Main Road, Area XYZ", 00000000
Estou executando o seguinte comando para substituir,dentro da coluna Endereço para|para carregá-lo no banco de dados.
awk '!(NR%2){gsub(",","|")} {printf RFS $0} {RFS="\""}' RS=\" fileName.txt > output.txt
O problema que estou enfrentando é que sempre que executei este comando ele me retornou o seguinte erro: Inicialmente estava rodando ok
awk: run time error: not enough arguments passed to printf(""Jake Lake%, Apartment #22, Main Road, Area XYZ")
Existe alguma solução para isso? eu percebi isso%está chegando no endereço, esse é o problema?
Responder1
- Para maior robustez, nunca do
printf $0
, sempre useprintf "%s", $0
em vez disso, pois o primeiro falhará quando sua entrada contiverprintf
caracteres de formatação (como você está vendo atualmente). O mesmo se aplica ao usoprintf
com quaisquer dados de entrada. - Para maior clareza e robustez, nunca use nomes de variáveis com letras maiúsculas, por exemplo,
RFS
para evitar conflitos com nomes de variáveis incorporadas e para evitar ofuscar seu código, fazendo parecer que você está usando uma variável incorporada quando não está. - Para facilitar a leitura, não defina variáveis, por exemplo
RS
, depois do seu script, a menos que você precise defini-las com valores diferentes para arquivos de entrada diferentes, defina variáveis antes ou no início do seu script para que, ao ler o seu script, vejamos elas sendo definidas antes de nós vê-los sendo usados. - Para eficiência, simplicidade, robustez, o primeiro argumento para *sub() é um regexp, não uma string, então use delimitadores regexp (
/.../
), e não string ("..."
), a menos que você PRECISE de um regexp dinâmico em vez de estático por algum motivo. - Para maior clareza e facilidade de manutenção, quando você tiver 2 variáveis que devem ter o mesmo valor, por exemplo,
RS
eRFS
, não as defina separadamente com o mesmo valor, por exemploRS="\""; RFS="\""
, configure-as juntas para esse valor, por exemplo,RS=RFS="\""
ou defina uma para a outra, por exemploRS="\""; RFS=RS
.
Veja como escrever o código da sua pergunta corretamente:
$ awk -v RS='"' '!(NR%2){gsub(/,/,"|")} {printf "%s%s", rfs, $0; rfs=RS}' file
First Name, Last Name, Address, Phone Number
John, Doe, "House # 11| Street xyz| Road| Area",00000000
Sara, Taylor, "Jake Lake%| Apartment #22| Main Road| Area XYZ", 00000000
Para fazer mais do que isso com um CSV usando o awk, consultequal é a maneira mais robusta de analisar com eficiência o csv usando o awk.
Responder2
O erro que você obtém é devido ao uso da concatenação do valor de RFS
(uma variável vazia) e $0
como string de formato com printf
.
Seu arquivo é um arquivo CSV válido, além de ter espaços após algumas vírgulas delimitadoras (o que atrapalha a citação do Address
campo; um campo entre aspas precisa ter o caractere de aspa inicial diretamente após o delimitador). Podemos corrigir isso usando csvformat
(parte do csvkit dehttps://csvkit.readthedocs.io/en/latest/):
$ csvformat --skipinitialspace file.csv >fixed-file.csv
$ cat fixed-file.csv
First Name,Last Name,Address,Phone Number
John,Doe,"House # 11, Street xyz, Road, Area",00000000
Sara,Taylor,"Jake Lake%, Apartment #22, Main Road, Area XYZ",00000000
Um banco de dados que possa analisar CSV deve ser capaz de ler isso como está.
Você ainda deseja substituir todas as vírgulas incorporadas por |
, simplesmente altere o delimitador do arquivo para algo diferente de uma vírgula (usarei as guias abaixo), altere todas as vírgulas restantes para barras verticais e volte a usar vírgulas como delimitadores novamente.
Podemos fazer isso diretamente nos dados originais:
$ csvformat --skipinitialspace --out-tabs file.csv | tr ',' '|' | csvformat --tabs >fixed-file.csv
$ cat fixed-file.csv
First Name,Last Name,Address,Phone Number
John,Doe,House # 11| Street xyz| Road| Area,00000000
Sara,Taylor,Jake Lake%| Apartment #22| Main Road| Area XYZ,00000000
As variantes curtas das várias opções longas usadas são -S
for --skipinitialspace
, -T
for --out-tabs
e -t
for --tabs
.