Remova nomes de usuários em um arquivo e substitua por um número incremental

6

Esta é uma questão de processamento de texto. Eu tenho 2 arquivos:

joeblogs
johnsmith
chriscomp
12:00:00 (AAA) OUT: "string" joeblogs@hostname
12:00:00 (AAA) OUT: "string" joeblogs@hostname
12:00:00 (AAA) OUT: "string" johnsmith@hostname
12:00:00 (AAA) OUT: "string" joeblogs@hostname
12:00:00 (AAA) OUT: "string" chriscomp@hostname

O arquivo 1 contém uma lista de nomes de usuários únicos que aparecem em um registro (arquivo 2).

Saída desejada

12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER2@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER3@hostname

Acho que não preciso dos dois arquivos. O arquivo 1 é gerado analisando o arquivo 2 para os nomes de usuário exclusivos. Minha lógica era obter uma lista de nomes de usuários que eu sei que aparecem no arquivo 2 e passá-los por ele, substituindo por sed .

Algo como:

for i in $(cat file1);do sed -e 's/$i/USER[X]';done

Em que USER[X] é incrementado com cada nome de usuário exclusivo.

No entanto, não posso fazer isso. Eu nem acho que a lógica é boa. Posso ter ajuda para alcançar o resultado desejado? awk / sed / grep / bash são bem-vindos.

    
por user288657 30.04.2018 / 17:09

4 respostas

9

Como você percebeu que você "não precisa dos 2 arquivos" , use a seguinte awk solução para processar o log inicial arquivo em uma passagem:

awk '{
         u_name = substr($5, 1, index($5, "@"));
         if (!(u_name in users)) users[u_name] = ++c;
         sub(/^[^@]+/, "USER" users[u_name], $5)
     }1' file.log

A saída:

12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER2@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER3@hostname
    
por 30.04.2018 / 17:19
6

Outro awk

awk '!($5 in a){a[$5]=++i}{sub("[^@]*","USER"a[$5],$5)}1' infile
    
por 30.04.2018 / 17:41
5

Com o bash você pode fazer:

n=0
declare -A users=()
while IFS= read -r line; do
    if [[ $line =~ ([^[:blank:]]+)@ ]]; then
        user=${BASH_REMATCH[1]}
        if [[ -z ${users[$user]} ]]; then
            users[$user]=USER$((++n))
        fi
        line=${line/$user/${users[$user]}}
    fi 
    echo "$line"
done < File2

ou um perl one-liner

perl -pe 's/(\S+)(?=@)/ $users{$1} ||= "USER".++$n /e' File2
    
por 30.04.2018 / 17:26
2

Com sed , você pode fazer isso:

$ sed "$(sed '=' File1 | sed -r 'N;s/(.*)\n(.*)/s%@hostname%USER@hostname%/')" File2
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER2@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER3@hostname
$ 

Existem 3 sed de comandos aqui. Os comandos sed 2 e 3 geram uma expressão sed fora do Arquivo1 que, por sua vez, é usado pelo comando 1 para processar o Arquivo2:

  • O comando 2 simplesmente acrescenta o número da linha após cada linha do arquivo1
  • O comando 3 reorganiza cada linha do Arquivo1 e seu número de linha seguinte em uma expressão sed para substituir, e. joeblogs@hostname com USER1@hostname e assim por diante para todos os usuários no Arquivo1
  • O Comando 1 usa a expressão sed gerada para processar todas as substituições no Arquivo2.
por 30.04.2018 / 23:15