Substituir a primeira coluna em um arquivo

3

Eu tenho o seguinte arquivo.

101; John Bauer;      811-7780831;
102; Anthony Higgins; 844-4317627; 
102; Anthony Higgins; 844-4317627;
103; Arnold Sipes;    866-4343123;
104; Donald Quinn;    877-2828732;
105; Roy Jaeger;      551-2323001;
105; Roy Jaeger;      551-2323001;
105; Roy Jaeger;      551-2323001;

Estou tentando usar sed para substituir a primeira coluna do arquivo pelos valores de incremento automático, começando com um. O resultado final deve ser algo assim.

1; John Bauer;      811-7780831;
2; Anthony Higgins; 844-4317627; 
2; Anthony Higgins; 844-4317627;
3; Arnold Sipes;    866-4343123;
4; Donald Quinn;    877-2828732;
5; Roy Jaeger;      551-2323001;
5; Roy Jaeger;      551-2323001;
5; Roy Jaeger;      551-2323001;

Se o primeiro valor da primeira coluna se repetir, ele deve atribuir o mesmo valor, portanto, os valores duplicados no arquivo "output".

Isso é possível?

    
por gm_will 04.02.2016 / 18:36

2 respostas

1

Usando o Perl:

perl -F\; -lane 'BEGIN {$, = ";"} $F[0] = $F[0] - 100; print(@F)' file

Para editar o arquivo no local:

perl -i -F\; -lane 'BEGIN {$, = ";"} $F[0] = $F[0] - 100; print(@F)' file
  • -i : especifica que os arquivos processados pelo "< >" construções devem ser editadas no local.
  • -F\; : define o separador do campo de entrada para ;
  • -l : ativa o processamento automático de finalização de linha. Tem dois efeitos separados. Primeiro, ele automaticamente efetua chps $ / (o separador de registro de entrada) quando usado com -n ou -p. Segundo, ele atribui $ \ (o separador de registro de saída) para ter o valor de octnum, de forma que quaisquer instruções de impressão tenham esse separador novamente incluído. Se octnum for omitido, define $ \ para o valor atual de $ /.
  • -a : ativa o modo de preenchimento automático quando usado com um -n ou -p. Um comando split implícito para o array @F é feito como a primeira coisa dentro do loop while implícito produzido por -n ou -p.
  • n : faz com que o Perl assuma o seguinte loop em torno do seu programa, o que faz com que seja iterado sobre argumentos de nome de arquivo como sed -n ou awk:

    LINE:
      while (<>) {
          ...             # your program goes here
      }
    
  • -e : pode ser usado para inserir uma linha de programa.
  • BEGIN {$, = ";"} $F[0] = $F[0] - 100; print(@F) : define o separador do campo de saída como ; , atribui o primeiro campo a seu valor diminuído em 100 e imprime o registro.
% cat file
101; John Bauer;      811-7780831;
102; Anthony Higgins; 844-4317627; 
102; Anthony Higgins; 844-4317627;
103; Arnold Sipes;    866-4343123;
104; Donald Quinn;    877-2828732;
105; Roy Jaeger;      551-2323001;
105; Roy Jaeger;      551-2323001;
105; Roy Jaeger;      551-2323001;
% perl -F\; -lane 'BEGIN {$, = ";"} $F[0] = $F[0] - 100; print(@F)' file
1; John Bauer;      811-7780831
2; Anthony Higgins; 844-4317627; 
2; Anthony Higgins; 844-4317627
3; Arnold Sipes;    866-4343123
4; Donald Quinn;    877-2828732
5; Roy Jaeger;      551-2323001
5; Roy Jaeger;      551-2323001
5; Roy Jaeger;      551-2323001
    
por kos 04.02.2016 / 20:31
2

Seu padrão é basicamente "fazer a primeira coluna igual ao valor - 100". AWK é apropriado para isso

$ awk -F';' 'BEGIN{OFS=";"}{$1=$1-100;print }' personList.txt  
1; John Bauer;      811-7780831;
2; Anthony Higgins; 844-4317627; 
2; Anthony Higgins; 844-4317627;
3; Arnold Sipes;    866-4343123;
4; Donald Quinn;    877-2828732;
5; Roy Jaeger;      551-2323001;
5; Roy Jaeger;      551-2323001;
5; Roy Jaeger;      551-2323001;

Não há edição no local, portanto, redirecione a saída para um novo arquivo.

$ awk -F';' 'BEGIN{OFS=";"}{$1=$1-100;print }' personList.txt  | tee newFile.txt
1; John Bauer;      811-7780831;
2; Anthony Higgins; 844-4317627; 
2; Anthony Higgins; 844-4317627;
3; Arnold Sipes;    866-4343123;
4; Donald Quinn;    877-2828732;
5; Roy Jaeger;      551-2323001;
5; Roy Jaeger;      551-2323001;
5; Roy Jaeger;      551-2323001;

Para resolver o que você pediu nos comentários (tornando o campo # 4 "Não disponível" se estiver vazio), você pode testar 4 caracteres de dígito de classe usando if statement e regex

$ awk -F';' 'BEGIN{OFS=";"}{$1=$1-100; if ($4 !~ /[[:digit:]]{4}/) $4=" N/A"  ;print }' personList.txt 

1; John Bauer;      811-7780831; 1001;
2; Anthony Higgins; 844-4317627; N/A;
2; Anthony Higgins; 844-4317627; N/A;
3; Arnold Sipes;    866-4343123; N/A;
4; Donald Quinn;    877-2828732; N/A;
5; Roy Jaeger;      551-2323001; 1267;
5; Roy Jaeger;      551-2323001; 1273;
5; Roy Jaeger;      551-2323001; 1204;

Como alternativa, você poderia fazer algo assim com a instrução if

if ( $4 !~ /.*[0-9].*/ )
    
por Sergiy Kolodyazhnyy 04.02.2016 / 18:44