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 %3
e %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 %123
tokens 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 \1
referê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 grep
parte remove todas %123
as linhas não simbólicas.
Responder2
Talvez seja melhor usar grep -o
neste caso:
grep -oP '\B%[0-9]{1,3}\b' inputfile
Supondo que sua versão grep
suporte 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 %digit
combo - 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.