Linux - como eu ignoro caracteres especiais entre “”?

1

Meu arquivo: (1 linha de amostra)

MMP,"01_janitorial,02_cleaning_tools",1,,CUBIC_INCH,"(14) tray capacity, 6" upright with 3" spacing, mounts on 48"W x 24"D, taupe epoxy, fits MetroMax i
& MetroMax Q shelf, NSF",CLEANING

Eu preciso ler isso em uma tabela do Postgresql com 7 colunas.

Divisão de colunas:

  1. MMP
  2. "01_janitorial,02_cleaning_tools"
  3. 1
  4. CUBIC_INCH
  5. "(14) tray capacity, 6" upright with 3" spacing, mounts on 48"W x 1. 24"D, taupe epoxy, fits MetroMax i & MetroMax Q shelf, NSF"
  6. CLEANING

O arquivo é basicamente delimitado por vírgula, mas preciso ignorar as vírgulas, o retorno de carro (se presente) e as aspas duplas SE o texto estiver entre aspas duplas. Como nas colunas 2 e 6.

Eu posso usar o comando postgresql copy para carregar, ou converter o arquivo usando awk, perl, sed ou o que for para converter o arquivo e então carregar.

    
por J.Turck 03.01.2018 / 22:16

4 respostas

0

O uso de -F, geralmente não é suficiente para analisar um arquivo CSV. Especialmente se, como descrito, o delimitador puder fazer parte de uma string entre aspas. Você pode contornar alguns usando FPAT para usar uma expressão para definir um campo, em vez de definir um caractere para o delimitador de campo, mas awk continuará linha por linha, então você terá que consumir preemptivamente as quebras de linha nos seus dados.

Uma vez feito, você pode fazer algo como awk 'BEGIN {FPAT="([^,]+)|(\"[^\"]+\")"} { /* normal processing here */ }' /path/to/file .

Essa expressão definirá como um campo "qualquer coisa que não seja uma vírgula" ou "Uma aspa dupla, uma ou mais de qualquer coisa que não seja uma aspa dupla, seguida de uma aspa dupla".

Isso, no entanto, explodirá se qualquer um dos seus dados citados eles contiverem aspas duplas.

    
por 03.01.2018 / 22:26
0

Como foi dito, o arquivo foi gerado incorretamente. No entanto, você pode tentar usá-lo usando não apenas , delimiter mas também ", e ," . Claro, script personalizado será necessário e sem garantia você não vai encontrar algo parecido em seu sexto campo.

Alternativamente, você pode despir os primeiros cinco campos, assumindo que o 6º campo é o único que foi desfeito e, a partir do resultado, cortar o último campo e vírgula. Os restos mortais serão o sexto conteúdo de campo.

    
por 04.01.2018 / 00:44
0

A solução será muito específica para o seu arquivo de dados, já que as citações não foram devidamente removidas. Como há apenas uma coluna de problemas, é bem factível. Aqui vai você:

#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
    echo "Line: $line"

# grabbing the first field is easy ..
    f1=$(echo $line | cut -d, -f1 )

# now remove the first field from the line
    line=$(echo $line | sed "s/$f1,//" )
    echo "Line is now: $line"

# to grab the second field use quote as a delimiter
    f2=$(echo $line | cut -d\" -f2 )

# now remove the second field from the line
    line=$(echo $line | sed "s/\"$f2\",//" )
    echo "Line is now: $line"

# fields 3,4,5 are trivial .. just repeat the same pattern as 1 and then remove them
    f3=$(echo $line | cut -d, -f1 )
    line=$(echo $line | sed "s/$f3,//" )
    echo "Line is now: $line"
    f4=$(echo $line | cut -d, -f1 )
    line=$(echo $line | sed "s/$f4,//" )
    echo "Line is now: $line"
    f5=$(echo $line | cut -d, -f1 )
    line=$(echo $line | sed "s/$f5,//" )

# here is the "trick" ... reverse the string, then you can cut field 7 first!
    line=$(echo $line | rev)
    echo "Line is now: $line"
    f7=$(echo $line | cut -d, -f1 )

# now remove field 7 from the string, then reverse it back
    line=$(echo $line | sed "s/$f7,//" )
    f7=$(echo $f7 | rev)

# now we can reverse the remaining string, which is field 6 back to normal
    line=$(echo $line | rev)
# and then remove the leading quote
    line=$(echo $line | cut --complement -c 1)
# and then remove the trailing quote
    line=$(echo $line | sed "s/\"$//" )
    echo "Line is now: $line"
# and then double up all the remaining quotes
    f6=$(echo $line | sed "s/\"/\"\"/g" )

    echo f1 = $f1
    echo f2 = $f2
    echo f3 = $f3
    echo f4 = $f4
    echo f5 = $f5
    echo f6 = $f6
    echo f7 = $f7
    echo $f1,\"$f2\",$f3,$f4,$f5,\"$f6\",$f7 >> fixed.txt
done < "$1"

Eu fiz isso ecoar muitos resultados para mostrar como funciona, você pode remover todas as instruções de eco para torná-lo mais rápido depois de entendê-lo. Acrescenta a linha fixa a fixed.txt .

Aqui está um exemplo de execução e saída:

[root@alpha ~]# ./fixit.sh test.txt
Line: MMP,"01_janitorial,02_cleaning_tools",1,,CUBIC_INCH,"(14) tray capacity, 6" upright with 3" spacing, mounts on 48"W x 24"D, taupe epoxy, fits MetroMax i & MetroMax Q shelf, NSF",CLEANING
Line is now: "01_janitorial,02_cleaning_tools",1,,CUBIC_INCH,"(14) tray capacity, 6" upright with 3" spacing, mounts on 48"W x 24"D, taupe epoxy, fits MetroMax i & MetroMax Q shelf, NSF",CLEANING
Line is now: 1,,CUBIC_INCH,"(14) tray capacity, 6" upright with 3" spacing, mounts on 48"W x 24"D, taupe epoxy, fits MetroMax i & MetroMax Q shelf, NSF",CLEANING
Line is now: ,CUBIC_INCH,"(14) tray capacity, 6" upright with 3" spacing, mounts on 48"W x 24"D, taupe epoxy, fits MetroMax i & MetroMax Q shelf, NSF",CLEANING
Line is now: CUBIC_INCH,"(14) tray capacity, 6" upright with 3" spacing, mounts on 48"W x 24"D, taupe epoxy, fits MetroMax i & MetroMax Q shelf, NSF",CLEANING
Line is now: GNINAELC,"FSN ,flehs Q xaMorteM & i xaMorteM stif ,yxope epuat ,D"42 x W"84 no stnuom ,gnicaps "3 htiw thgirpu "6 ,yticapac yart )41("
Line is now: (14) tray capacity, 6" upright with 3" spacing, mounts on 48"W x 24"D, taupe epoxy, fits MetroMax i & MetroMax Q shelf, NSF
f1 = MMP
f2 = 01_janitorial,02_cleaning_tools
f3 = 1
f4 =
f5 = CUBIC_INCH
f6 = (14) tray capacity, 6"" upright with 3"" spacing, mounts on 48""W x 24""D, taupe epoxy, fits MetroMax i & MetroMax Q shelf, NSF
f7 = CLEANING

Se você precisar escapar das citações de alguma outra maneira, isso deve ser bastante óbvio, considerando o que foi dito acima.

    
por 04.01.2018 / 05:50
0

Eu obtenho o produto final removendo retornos de carro dentro de um registro citado como o seguinte script:

$ cat remove_cr.awk
#!/usr/bin/awk -f
{ record = record $0
  # If number of quotes is odd, continue reading record.
  if ( gsub( /"/, "&", record ) % 2 )
  { record = record " "
    next
  }
}
{ print record
  record = ""
}
    
por 08.01.2018 / 18:50