GAWK usando parênteses como FS

0

Eu tenho lutado com o funcionamento do gawk ao configurar um regexp para o FS como space_about_parenthers OU closing_parenthesis-coma-space Eu tentei várias abordagens nenhuma com o comportamento desejado em primeiro lugar. FS="( ()|(), )" 2º. FS="[( ()(), )]" 3rd (pelo código ASCII OCT) FS="[(00)(140)]" 4th FS="((00)|(140))"

meu arquivo de entrada é este link é um arquivo com apenas um registro (linha) do meu log do apt-get no Debian listando alguns pacotes.

meu programa gawk é esse

#! /usr/bin/gawk -f
BEGIN {FS = "[(00)(140]"}
{
for(i=1;i<=NF;i=i+2) #I increased i by 2 because i want to print the odd numbered fields(only the names of the packages:architecture)  
    print $i
}'

Eu vou executar isso no bash como myawk.awk input.txt > output.txt

Eu adorarei incluir uma grande palavra aqui FXXX !!!! Porque acabei de resolver isso. Eu acho que, como recompensa, continue tentando. Eu usei FS = "(\s\0)|(\1,\s)" e isso funcionou mesmo porque eu não entendo porque três barras invertidas \\ antes do código ASCII oct.

Alguém ofereceria alguma explicação sobre isso? Por que? Eu li que o AWK leu um regex duas vezes e isso exigirá \ , mas eu precisei de \\ (três !!!).

Além disso, quaisquer abordagens alternativas ou diferentes serão muito apreciadas!

Obrigado antecipadamente!

este é o meu resultado desejado e, felizmente, como consegui do meu último link ( uma lista de pacotes com sua arquitetura)

    
por alejo4373 21.02.2017 / 05:53

3 respostas

1

Você pode ter pensado nisso. Um pouco. Eu tenho que trabalhar com FS=" \(|\), " , e até consegui encurtá-lo para FS=" \(|), " .

  • Você parecia acreditar que precisava fazer %código%, quando tudo que você precisava fazer era "(regex1)|(regex2)" .
  • Você parecia acreditar nisso cercando parênteses em parênteses de agrupamento, os parênteses internos se tornariam parênteses textuais e literais. Não funciona assim. O agrupamento de expressões regulares pode aninhar-se; para tratar parênteses como parênteses textuais literais, você precisa escapar deles.
  • "regex1|regex2" é especial em uma expressão regular somente dentro de um grupo. Se o ) tiver escapado, o ( não precisa ser.

Aqui é onde fica complicado. Ingenuamente, acima, ) deve ser bom o suficiente. Mas o GAWK tem um problema com expressões regulares nas constantes de string; é discutido em Guia do usuário do GNU Awk, Seção 9.1.3.1 . Ele se concentra em obter um literal FS=" \(|), " no texto de substituição para uma chamada & , sub() ou gsub() , mas parece aplicar-se também a gensub() :

… there are several levels of escape processing going on.

First, there is the lexical level, which is when awk reads your program and builds an internal copy of it to execute.  Then there is the runtime level, which is when awk actually scans the [program and determines how to execute it].

At both levels, awk looks for a defined set of characters that can come after a backslash.  At the lexical level, it looks for the escape sequences listed in Escape SequencesThus, for every ‘\’ that awk processes at the runtime level, you must type two backslashes at the lexical level.  …

Ênfase (última sentença) adicionada. O que isso parece dizer é que, se quisermos definir FS para FS (para escapar do parêntese esquerdo, para tratar os parênteses como um parêntese textual literal), você precisa atribuir " \(|), " ou especificar FS=" \(|), " (para escapar das barras invertidas). Você pode verificar isso com um teste simples: Execute -F' \(|), ' e, em seguida, imprima awk -F' \(|), ' de dentro do seu programa. Será exibido como FS .

Em geral, se você quiser transformar um caractere especial em um caractere não-especial (ou, ocasionalmente, vice-versa), a abordagem comum e tradicional é escapar com um ⁠ \(|), ⁠ (barra invertida). Mas há outro mecanismo específico para expressões regulares: use uma expressão \ . Os únicos caracteres especiais em expressões […] são […] , ^ e - (e isso depende da posição).

  • ] significa [pq] ou p
  • q significa [()] ou (
  • ) significa [(p] ou (
  • p significa [(] ou ... bem, como não há outros caracteres, Significa apenas um literal ( .

Então, se você é alérgico a barras invertidas, pode definir ( .

    
por 21.02.2017 / 08:32
0

Aqui está uma abordagem alternativa que eu criei. Ele corresponde exatamente à sua saída. É provavelmente menos eficiente devido à operação split() adicional para cada item, mas é mais fácil de ler e entender.

#!/usr/bin/awk -f

BEGIN { 
    FS="), "
}
{
    sub(/^Install:/, "") 
    for (i=1; i<=NF; i++) { 
        split($i, a, " ")
        print a[1]
    }
}
    
por 21.02.2017 / 07:07
0

Existe uma maneira muito mais simples de realizar a mesma tarefa sem usar o awk. Você pode usar expressões regulares Perl com muitas das versões do grep que vêm nas principais distribuições do Linux. Com a minha versão do grep (GNU grep versão 2.27) o seguinte fornece a mesma saída que a solução awk.

grep -oP '(?<=\),).*?(?=\()' input.txt > output.txt
    
por 21.02.2017 / 13:42