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

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

Como posso substituir tudo em uma string por sed, exceto% e qualquer número que o suceda diretamente? Ou seja, tudo, exceto strings como:

%1 %1000 %55 etc.

Dadas strings deste formato:

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

Eu só quero pegar as peças %3e %4. Os números podem ir até 999.

Responder1

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

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

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

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

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

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

Outra variante:

$ sed 's/\(%[0-9]\+\)/\n\1\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 tubo. Em seguida, a grepparte remove todas %123as linhas não simbólicas.

Responder2

Talvez seja melhor usar grep -oneste caso:

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

Supondo que sua versão grepsuporte expressões regulares compatíveis com Perl ( -P). De outra forma:

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

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

sed 'y/ /\n/' inputfile | sed '/^%[0-9]\{1,\}/!d'

Responder3

Ao trabalhar com sedé quase sempre aconselhável:

/address then/s/earch/replace/

Há duas razões para isso. A primeira é que com múltiplas linhas /addressing/é mais rápido - é otimizado apenas paraencontraruma correspondência e não se preocupa em selecionar apenas partes de uma linha para edição e assim pode restringir os resultados mais cedo.

A segunda razão é que você pode executar várias operações de edição no mesmo endereço - isso torna as coisas muito mais fáceis.

É claro que, neste caso, dados apenas os dados que você mostra, não faz 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ãonão-%caracteres desde o início da linha e todosnão numéricocaracteres do final da linha no endereço e, em seguida, remove-os com s///- e pronto.

Na sua forma atual, ele pode distorcer os dados de maneiras inesperadas se você alimentá-los com linhasnãocontendo um %digitcombo - e é por isso que o endereçamento é importante. Se alterarmos um pouco:

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

Fica mais seguroemais rápido.

Responder4

Minha solução não usa sed, mas grep com regex estendido e opções 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.

informação relacionada