¿Cómo sed -e 's///' todo excepto un patrón específico?

¿Cómo sed -e 's///' todo excepto un patrón específico?

¿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 %3y %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 %123tokens 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 \1referencia 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 greppieza elimina todas %123las líneas que no son simbólicas.

Respuesta2

Quizás sea mejor que uses grep -oen este caso:

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

Suponiendo que su versión grepadmita 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 sedcasi 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 %digitcombo, 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.

información relacionada