Mova o padrão para o início da linha

5

Estou tentando reformatar um arquivo de log para que a data e a hora apareçam no início da linha. Meus registros são assim:

blah, blah, blah, Friday, Mar 13,2015 16:59:42
yadi, yadi, yada, Friday, Mar 13,2015 16:51:11

Eu gostaria que eles ficassem assim:

Friday, Mar 13,2015 16:59:42 blah, blah, blah
Friday, Mar 13,2015 16:51:11 yadi, yadi, yada

Eu fui tão longe a ponto de encontrar o padrão grep correto com grep -o -i -e '[a-zA-Z]*, [a-z][a-z][a-z] [0-9]*,[0-9][0-9][0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]' ~/log.txt .

Como posso mover esses resultados de padrão para a esquerda da string de informações? Obrigado pela sua ajuda.

    
por Tfb9 21.03.2015 / 21:42

3 respostas

5

Teste sed com o seguinte regex:

$ sed -i.bak 's_\(.*\),[[:blank:]]\([[:alpha:]]\+,[[:blank:]][[:alpha:]]\+[[:blank:]][[:digit:]]\+,[^,]\+$\)_ _' file.txt 
Friday, Mar 13,2015 16:59:42 blah, blah, blah
Friday, Mar 13,2015 16:51:11 yadi, yadi, yada

Aqui usamos o método de substituição de grupo sed para obter o resultado desejado.

  • \(.*\) corresponderá até blah, blah, blah , pois temos ,[[:blank:]] para corresponder a , depois disso.
  • \([[:alpha:]]\+,[[:blank:]][[:alpha:]]\+[[:blank:]][[:digit:]]\+,[^,]\+$\) corresponderá à parte restante da linha (a parte que queremos colocar no início).

Em seguida, temos para colocar o segundo grupo primeiro e depois um espaço e depois o primeiro grupo.

Será feito o backup do arquivo original como file.txt.bak , se você não quiser usar apenas -i em vez de -i.bak .

** Embora você tenha a saída desejada, usar o Regex / sed não será a solução ideal nesse caso.

EDITAR: Se você tem uma linha como [Internet disconnected] Friday, Mar 13,2015 15:48:34 , tente isto:

$ sed -i.bak 's_\(.*[^,]\),*[[:blank:]]\([[:alpha:]]\+,[[:blank:]][[:alpha:]]\+[[:blank:]][[:digit:]]\+,[^,]\+$\)_ _' file.txt 
Friday, Mar 13,2015 15:48:34 [Internet disconnected]
Friday, Mar 13,2015 16:59:42 blah, blah, blah
Friday, Mar 13,2015 16:51:11 yadi, yadi, yada

Na regex anterior, tínhamos \(.*\),[[:blank:]] (uma vírgula e um espaço em branco após o primeiro grupo correspondente), agora para incluir a nova linha na saída, fizemos o primeiro grupo correspondente \(.*[^,]\) para garantir que ele não terminamos com uma vírgula e depois combinamos ,* , isto é, uma ou mais vírgulas. Portanto, o novo comando sed funcionará para todos os casos mencionados.

    
por heemayl 21.03.2015 / 22:13
4

com o awk é uma sintaxe muito mais simples

awk -F, '{print ","","","","","}' file.txt
    
por Panther 21.03.2015 / 22:15
3

A regra de ouro das expressões regulares é "menos é mais". Você deve sempre tentar escrever o regex mais simples que corresponda aos seus dados. Isso não só torna muito mais fácil de ler e entender, mas também é muito mais robusto e não quebra com pequenas mudanças no formato. Então, no seu caso, você poderia simplesmente fazer:

$ sed -r 's/(.*), ([^,]+,[^,]+,[^,]*$)//' file 
Friday, Mar 13,2015 16:59:42blah, blah, blah, 
Friday, Mar 13,2015 16:51:11yadi, yadi, yada, 

Combina tudo desde o início da linha até uma vírgula e espaço ( (.*), ) e, como o padrão está entre parênteses, o salva como . Agora, porque o segundo grupo capturado (segundo padrão entre parênteses) vai até o final da linha (é isso que o $ significa), sabemos que estamos combinando a parte direita na primeira.

O segundo procura um trecho de um ou mais caracteres não-vírgula ( [^,]+ ), uma vírgula, outro conjunto de não-vírgulas, outra vírgula e, em seguida, tantos caracteres não-vírgula quanto possível até o final do linha. Dessa forma, podemos identificar corretamente os últimos campos como a data. O s/// é o operador de substituição que simplesmente altera a ordem do primeiro e segundo padrão capturado.

Você também pode fazer a mesma coisa em awk . Presumivelmente, o texto antes da data é variável, então não podemos assumir o mesmo número de campos para cada linha. Portanto, precisaremos contar os campos para trás no final da linha:

$ awk -F, '{ 
            printf "%s,%s,%s, ", $(NF-2),$(NF-1),$NF; 
            for(i=1;i<NF-3;i++){printf "%s,", $i} print $(NF-3)
         }' file 
 Friday, Mar 13,2015 16:59:42, blah, blah, blah
 Friday, Mar 13,2015 16:51:11, yadi, yadi, yada

Ou em Perl:

$ perl -lpe 's/(.*), ([^,]+,[^,]+,[^,]*$)/, /' file 
Friday, Mar 13,2015 16:59:42, blah, blah, blah
Friday, Mar 13,2015 16:51:11, yadi, yadi, yada

$ perl -F, -lane 'print join ",",@F[$#F-2,$#F-1,$#F,0..$#F-3]' file 
 Friday, Mar 13,2015 16:59:42,blah, blah, blah
 Friday, Mar 13,2015 16:51:11,yadi, yadi, yada
    
por terdon 22.03.2015 / 12:50

Tags