Simples uso significativo do sufixo de endereço de várias linhas '/ M'?

3

Para o% GNUsed v4.2.2-7, info sed diz:

'/REGEXP/M'
'\%REGEXP%M'
     The 'M' modifier to regular-expression matching is a GNU 'sed'
     extension which directs GNU 'sed' to match the regular expression
     in 'multi-line' mode.  The modifier causes '^' and '$' to match
     respectively (in addition to the normal behavior) the empty string
     after a newline, and the empty string before a newline.  There are
     special character sequences ('\'' and '\'') which always match the
     beginning or the end of the buffer.  In addition, the period
     character does not match a new-line character in multi-line mode.

Não há nenhum exemplo dado. Após o teste, não é óbvio o que esse sufixo /M realmente faz . Parece se comportar como não /M em tudo.

Então, o que é um uso significativo simples de /M ? Onde "mais simples" significa "olá mundo" simples, nada que exija muito mais conhecimento adicional de outros programas, e "significante" significa que deve fazer algo perceptível com '/ M' que não pode ser feito se estiver faltando.

Como, por exemplo, uma instância de:

seq 10 | sed -n '<code>;/<some regexp>/Mp'

... que se comporta de maneira diferente de:

seq 10 | sed -n '<code>;/<some regexp>/p'
    
por agc 27.07.2016 / 17:51

2 respostas

7

Esse é o equivalente do sinal m nos operadores perl regexp ou usando (?m) em regexps perl ou PCREs (embora gsed ' M flag também remova o s perl flag, como sem M , sed . corresponde à nova linha, enquanto com perl , você precisa da s sinalizador para . para corresponder à nova linha).

Esses sinalizadores só entram em ação quando o espaço de padrão contém mais de uma linha, como quando usamos -z (para ler registros delimitados por NUL) ou ao adicionar linhas ao espaço de padrão com comandos como G , N ou s .

$ seq 3 | sed 'N;s/$/<foo>/g'
1
2<foo>
3
$ seq 3 | sed 'N;s/$/<foo>/Mg'
1<foo>
2<foo>
3

Após N , o espaço padrão contém 1<newline>2 . Sem M , $ corresponde apenas no final do espaço padrão, (após 2 ); com M , $ corresponde a ambos no final da primeira linha desse espaço padrão (depois de 1 , mas antes da nova linha), e no final o espaço padrão, (depois de 2 ).

    
por 27.07.2016 / 17:59
2

Como Stéphane apontou, esse modificador é útil quando o espaço de padrão contém mais de uma linha. Aqui estão mais alguns exemplos usando 'H;1h;$!d;x , que acumula todas as linhas no buffer de retenção e, na última linha, troca buffers de modo que toda a entrada esteja no espaço padrão. Então, com esta entrada:

printf %s\n 'onetwo' 'four' 'fivetwo' | sed 'H;1h;$!d;x;l;d'

é assim que o espaço padrão se parece:

onetwo\nfour\nfivetwo$

M pode ser útil

  • se você precisa combinar o começo e / ou o fim de algumas ou todas as linhas no espaço padrão :

    printf %s\n 'onetwo' 'four' 'fivetwo' | sed 'H;1h;$!d;x;s/^/DO/M2;s/$/END/Mg'
    
    onetwoEND
    DOfourEND
    fivetwoEND
    
  • se você estiver tentando encontrar uma correspondência que não ultrapasse várias linhas:

    printf %s\n 'onetwo' 'four' 'fivetwo' | sed 'H;1h;$!d;x;s/one.*two/MATCH/M'
    
    MATCH
    four
    fivetwo
    
  • se você quiser manipular o espaço de padrão sob a condição de que alguma linha no espaço de padrão inicie ou termine com um determinado padrão (este é um exemplo em que não é usado em conjunto com s : excluir espaço de padrão se uma linha terminar em ur ):

    printf %s\n 'onetwo' 'four' 'fivetwo' | sed 'H;1h;$!d;x;/ur$/Md'
    

Em todos esses exemplos, se você remover M , o resultado será bem diferente. No entanto, isso não significa que o acima não pode ser feito sem M , é apenas mais conveniente:

s/one.*two/MATCH/M'

vs

s/one[^\n]*two/MATCH/'

ou

/ur$/Md'

vs

/ur$\|ur\n/d'
    
por 27.07.2016 / 23:41