encontra a primeira linha que começa com a palavra-chave após outra palavra-chave

3

vamos apresentar meu problema para explicar melhor. Estou usando o cygwin, a instalação é baseada em um setup.ini com o seguinte formato:

    @ package-name
    sdesc: "short description, on one line"
    ldesc: "long description of arbitrary length, commonly multiple lines"
    category: categories in which the packege belonges, one line
    requires: packages (libs etc) required by this package, one line

então vem o seguinte pacote, & assim por diante.

O que eu preciso é, dado um nome de pacote, enviar todos os pacotes requeridos por este pacote (sem o prefixo 'requer', se possível).

Tenho certeza que é grep básico, mas sou novo por lá. obrigado.

    
por Philomath 11.07.2011 / 13:22

3 respostas

5

Eu não sei como você vai fazer isso com o grep, mas para essas tarefas eu prefiro o awk. Isso dá mais controle sobre o que eu quero fazer. embora eu não seja especialista em awk e ainda esteja aprendendo, mas aqui está como eu teria conseguido isso.

PKGNAM="package-name"; awk "/$PKGNAM\$/,/requires:/ { if ( \
PKGNAM="package-name"; awk "/$PKGNAM\$/,/requires:/ { if ( \%pre% ~ /requires:/ ) { sub( /^requires:.?/, \"\"  ); print } }"
~ /requires:/ ) { sub( /^requires:.?/, \"\" ); print } }"

UPDATE: atualizou o comando awk do exemplo, agora ele usa a variável PKGNAM para combinar com o nome do pacakge.

HTH.

    
por 11.07.2011 / 15:49
3

O grep trata todas as linhas independentemente, por isso não pode fazer o trabalho sozinho.

Awk é uma ferramenta geral de processamento de texto. Mantenha o controle de qual é o pacote atual (na variável p ) e imprima uma correspondência se uma linha requires: for encontrada no pacote correto (removendo o prefixo requires: ).

<setup.ini awk -vpackage='NAME_OF_PACKAGE' '
    sub(/^@ */,"") {p=$0}
    p==package && sub(/^requires: */,"") {print}
'

Outra abordagem do awk é processar entradas delimitadas por sequências newline- @ em vez de novas linhas. Ou, como as seções do pacote têm uma linha em branco entre elas, processe input por parágrafo: passe uma string vazia como o separador de registro RS (o que significa que os registros são separados por uma ou mais linhas em branco). Em seguida, para cada linha no registro procurado, se a linha começar com requires: , imprima-a (menos o prefixo).

<setup.ini awk -vpackage='NAME_OF_PACKAGE' -vRS= -vFS='\n' '
    sub(/^@ */,"") && $1==package {
        for (i=2; i<NF; i++) {if (sub(/^requires: */,"",$i)) print $i}
    }'

Outra possibilidade é o modo de parágrafo do Perl ( -00 ). Se o parágrafo começar com o cabeçalho direito ( /REGEXP/m significa uma correspondência multilinha, para que $ âncora signifique fim de linha em vez de fim de seqüência) e contenha uma linha requires: , imprima essa linha (menos o prefixo).

<setup.ini package=NAME_OF_PACKAGE perl -00 -ne '
    /\A@ *$ENV{package}$/m and /^requires: *(.*)$/m and print "$1\n"'

E aqui está uma para os amantes do sed (GNU). (Você não é esperado para entender isso.)

sed -ne '/^@/ { h; b; }; G; s/^requires: *\(.*\)\n@ *NAME_OF_PACKAGE$//p'
    
por 11.07.2011 / 16:41
1

Aqui está uma solução sed que pode fazer isso sem uma referência anterior.

# cf. "3.3. Addressing and address ranges",
# http://sed.sourceforge.net/sedfaq3.html#s3.3 (esp. (6) Relentless. ...)

PKGNAME="package-name"
sed -ne '/^ *@ *'"${PKGNAME}"'/{
:a
N
/\n *requires: /!ba
s/.*\n *requires: *//
p
}' setup.ini 

As soluções Gilles '(GNU) sed funcionam no Mac OS X 10.6.7 (usando FreeBSD sed) se o comando b for colocado em uma linha separada (ou pelo menos seguida por uma quebra de linha).

PKGNAME="package-name"
sed -ne '/^ *@ *'"${PKGNAME}"'/{h
b
};G;s/^ *requires: *\(.*\)\n *@ *'"${PKGNAME}"' *$//p' setup.ini
    
por 12.07.2011 / 14:59