Como posso selecionar colunas com base em um arquivo de controle com números de coluna inválidos?

0

Eu tenho que gerar o arquivo dinamicamente a partir do arquivo de origem com base no arquivo de controle abaixo.

control_file.txt 
1,3,5,-1,8,-1,4

O arquivo de controle contém a posição das colunas que eu preciso do arquivo de origem.

Exemplo: 1 coluna, 3 colunas, 5 colunas, coluna em branco (-1 indica coluna em branco) e assim por diante.

Eu escrevi um shell para ler a posição do arquivo de controle, um por um, para gerar vários arquivos. Então, finalmente, use o comando paste para gerar novos arquivos, no caso de -1 valores, criei arquivos de toque. Com base na sequência de ordem de arquivo, ela é colada pela opção ls-v .

Então, meu shell existente se parece com o seguinte:

if [ position != -1 ]
then
cut -d, -f$position > file_$var.csv 
else
touch file_$var.csv
fi
paste -d, $(ls -v file_*.csv) > newe_file.csv

Espero que haja uma maneira de minimizar a E / S de arquivos. Estou procurando algo abaixo:

cut -d, -f1,3,5 > file1.csv
touch file2.csv
cut -d, -f8 > file3.csv
touch file4.csv
cut -d, -f4 > file5.csv

Ou melhor solução será ótima.

O número de colunas nos arquivos de origem será na casa das centenas.

Resultados esperados:

input-file is sample.csv

col1,col2,col3,col4,col5,col6,col7,col8
1,2,3,4,5,6,7,8
9,10,11,12,13,14,15,16

output.csv:

col1,col3,col5,-1,col8,-1,col4
1,3,5,,8,,4
9,11,13,,16,,12

output.csv é baseado em controlfile.txt

    
por William R 18.09.2014 / 09:01

3 respostas

1

Outra resposta, um pouco mais simples que as outras:

#!/bin/bash
fields=$(sed -r -e 's/-1/ /g' -e 's/,/ FS /g' \
  -e 's/([0-9]+)/\$/g' control_file.txt)
awk -F, "{print ${fields}}" $1

O primeiro comando converte control_file.txt em um comando awk adequado:

$1 FS $3 FS $5 FS FS $8 FS FS $4

para executá-lo:

$ ./script.sh input.csv
col1,col3,col5,,col8,,col4
1,3,5,,8,,4
9,11,13,,16,,12

Na sua outra amostra:

$ ./script.sh sample.csv
BP ID,CurrentMonetary balance ,Provider contract id,,End Date,,charge Plan names 
1100001538,251,00000000000000000141,,18-Oct-12,,[B2] R2 LTE CHARGE PLAN 
1100003404,45.22,00000000000000009349,,23-Nov-13,,B0.3 ECS_CHARGE_PLAN DROP1 V3
    
por 18.09.2014 / 10:02
0

o arquivo awk

BEGIN { sp="-1" ;  FS="," ; }
FILENAME == "control.txt" { for (i=1;i<=NF;i++) col[i]=$i ;  next ;}
FILENAME != "control.txt" {
    comma="" ;
    for (i=1;i<NF;i++) {
            c=col[i] ;
            if (col[i]!=-1) printf "%s%s",comma,$c ;
            else printf "%s%s",comma,sp ;
            comma="," ;
    }
    printf "\n" ;
    sp="" ;
    }

a corrida

 awk -f a.awk control.txt  sample.txt
 col1,col3,col5,-1,col8,-1,col4
 1,3,5,,8,,4
 9,11,13,,16,,12

basicamente, a primeira linha no control.txt faz com que a coluna seja impressa.

    
por 18.09.2014 / 09:47
0
echo '1,2,3,4,5,6,7,8' |
sed 's/[^,]*//7;s///6;s///2;s/,,/,/
    s/\([^,]*\),\([^,]*\),,.*,\(.*\)/,,,,/'

Isso remove o conteúdo dos campos 7,6,2. Em seguida, remove o primeiro campo em branco. Em seguida, ele troca os três últimos campos não vazios como 2, 3, 1.

OUTPUT

1,3,5,,8,,4

E corra nos seus dados de amostra:

BP ID,CurrentMonetary balance ,Provider contract id,,End Date,,charge Plan names 
1100001538,251,00000000000000000141,,18-Oct-12,,[B2] R2 LTE CHARGE PLAN 
1100003404,45.22,00000000000000009349,,23-Nov-13,,B0.3 ECS_CHARGE_PLAN DROP1 V3

Então, novamente, desde que você possa verificar seu delimitador, você pode apenas usar o shell:

set -f; IFS=,
set -- $(cat file; echo "$IFS")
while [ $# -gt 8 ]
do printf %s\n "$1,$3,$5,,$8,,$4"
   shift "$(($#>7?8:$#))"
done

Com a opção shell, os campos podem conter qualquer coisa, exceto o delimitador. Contanto que você tenha um delimitador que seja diferente de <space><tab><newline> , os campos vazios serão preservados. Todos os caracteres que eles contêm - para incluir qualquer um desses três caracteres em branco - são preservados. Aqui eu uso uma vírgula. Você só precisa de memória suficiente para caber no arquivo.

    
por 18.09.2014 / 09:44