Como sed -e /// 'tudo, exceto um padrão específico?

4

Como posso substituir tudo em uma string por sed, exceto% e qualquer número que esteja diretamente conseguido? Significado, tudo, exceto strings como:

%1 %código% %código% etc.

Dadas strings desta forma:

    1: [18x14] [history 1/2000, 268 bytes] %3
    2: [18x14] [history 1/2000, 268 bytes] %4 (active)

Eu só quero obter as partes %1000 e %55 . Os números podem ir até %3 . Desculpe pela pergunta não clara.

    
por lord.garbage 05.05.2014 / 21:29

4 respostas

5
$ sed 's/^.*\(%[0-9]\+\).*$//' input

Supondo que uma linha contenha no máximo um desses %123 tokens e que cada linha contenha esse token.

O caractere meta \( \) marca um grupo de correspondência - que é então referenciado na substituição por meio da referência anterior . ^ / $ corresponde ao início / fim de uma linha.

Caso contrário, você poderá pré-filtrar a entrada, por exemplo:

$ grep '%[0-9]\+' input | sed 's/^.*\(%[0-9]\+\).*$//'

(quando nem todas as linhas contêm esse token)

Outra variante:

$ sed 's/\(%[0-9]\+\)/\n\n/g' | grep '%[0-9]'

(quando uma linha pode conter vários desses tokens)

Aqui estão as quebras de linha inseridas diretamente antes e depois de cada token - na primeira parte do pipe. Em seguida, a parte grep remove todas as linhas de token não %123 .

    
por 05.05.2014 / 22:03
6

Pode ser melhor utilizar grep -o neste caso:

grep -oP '\B%[0-9]{1,3}\b' inputfile

Assumindo que sua versão de grep suporta expressões regulares compatíveis com Perl ( -P ). Caso contrário:

grep -o '\B%[0-9]\{1,3\}\b' inputfile

Usando o GNU sed , pode-se transliterar espaços para novas linhas e obter as linhas desejadas:

sed 'y/ /\n/' inputfile | sed '/^%[0-9]\{1,\}/!d'
    
por 05.05.2014 / 21:59
3

Ao trabalhar com sed , é quase sempre aconselhável:

/address then/s/earch/replace/

Existem duas razões para isso. A primeira é que com várias linhas /addressing/ é mais rápido - ela é otimizada apenas para encontrar uma correspondência e não se incomoda em selecionar apenas partes de uma linha para edição e, assim, pode restringir os resultados mais rapidamente. / p>

A segunda razão é que você pode executar várias operações de edição fora do mesmo endereço - isso facilita muito as coisas.

É claro que, neste caso, dados apenas os dados mostrados, não fazem diferença prática. Ainda assim, é assim que eu faria o que você pergunta:

sed '/^[^%]*\|[^0-9]*$/s///g' <<\DATA
    1: [18x14] [history 1/2000, 268 bytes] %3
    2: [18x14] [history 1/2000, 268 bytes] %4 (active)
DATA

#OUTPUT
%3
%4

Ele apenas seleciona todos os caracteres que são caracteres não -% do início da linha e todos os caracteres não numéricos do final da linha no endereço e então os remove com s/// - e é isso.

Em sua forma atual, ele pode distorcer os dados de formas inesperadas se você alimentar linhas não contendo uma combinação %digit - e é por isso que o endereçamento é importante. Se alterarmos um pouco:

/%[0-9]/s/[^%]*\|[^0-9]*$//g

Torna-se mais seguro e mais rápido.

    
por 06.05.2014 / 08:58
2

Minha solução não usa sed mas grep com opções de extensão estendida e de correspondência única.


$ cat file
1: [18x14] [history 1/2000, 268 bytes] %3
2: [18x14] [history 1/2000, 268 bytes] %4 (active)
$ cat file | grep -Eo '%[0-9]+'
%3
%4

Usar grep neste caso é mais simples do que usar sed.

    
por 06.05.2014 / 16:39

Tags