¿Cómo puedo sustituir todo en una cadena con sed excepto % y cualquier número que lo suceda directamente? Es decir, todo excepto cadenas como:
%1
%1000
%55
etc.
Dadas cadenas de esta forma:
1: [18x14] [history 1/2000, 268 bytes] %3
2: [18x14] [history 1/2000, 268 bytes] %4 (active)
Sólo quiero obtener las piezas %3
y %4
. Los números pueden llegar hasta 999
.
Respuesta1
$ sed 's/^.*\(%[0-9]\+\).*$/\1/' input
Suponiendo que una línea contiene como máximo uno de esos %123
tokens y que cada línea contiene dicho token.
El \( \)
metacarácter marca un grupo de coincidencia, al que luego se hace referencia en la sustitución a través de la \1
referencia inversa. ^
/ $
coincide con el principio/final de una línea.
De lo contrario, puede filtrar previamente la entrada, por ejemplo:
$ grep '%[0-9]\+' input | sed 's/^.*\(%[0-9]\+\).*$/\1/'
(cuando no todas las líneas contienen dicho token)
Otra variante:
$ sed 's/\(%[0-9]\+\)/\n\1\n/g' | grep '%[0-9]'
(cuando una línea puede contener varios de esos tokens)
Aquí hay saltos de línea insertados directamente antes y después de cada ficha, en la primera parte de la tubería. Luego, la grep
pieza elimina todas %123
las líneas que no son simbólicas.
Respuesta2
Quizás sea mejor que uses grep -o
en este caso:
grep -oP '\B%[0-9]{1,3}\b' inputfile
Suponiendo que su versión grep
admita expresiones regulares compatibles con Perl ( -P
). De lo contrario:
grep -o '\B%[0-9]\{1,3\}\b' inputfile
Usando GNU sed
, se podrían transliterar espacios a nuevas líneas y obtener las líneas deseadas:
sed 'y/ /\n/' inputfile | sed '/^%[0-9]\{1,\}/!d'
Respuesta3
Cuando se trabaja con sed
casi siempre es recomendable:
/address then/s/earch/replace/
Hay dos razones para esto. La primera es que con varias líneas /addressing/
es más rápido: está optimizado sólo paraencontraruna coincidencia y no se molesta en seleccionar solo partes de una línea para editar y así puede limitar los resultados antes.
La segunda razón es que puedes realizar múltiples operaciones de edición desde la misma dirección, lo que hace las cosas mucho más fáciles.
Por supuesto, en este caso, dados sólo los datos que usted muestra, no hay ninguna diferencia práctica. Aún así, así es como haría lo que me preguntas:
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
Simplemente selecciona todos los personajes que estánno-%caracteres desde el principio de la línea y todosno numéricocaracteres del final de la línea en la dirección y luego los elimina con s///
- y eso es todo.
En su forma actual, podría alterar los datos de formas inesperadas si los alimenta con líneas.noque contiene un %digit
combo, y por eso es importante abordarlo. Si lo modificamos un poco:
/%[0-9]/s/[^%]*\|[^0-9]*$//g
Se vuelve más seguroymás rápido.
Respuesta4
Mi solución no usa sed sino grep con expresiones regulares extendidas y opciones de coincidencia ú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 en este caso es más sencillo que usar sed.