Si calificas la palabra para que signifique cualquier secuencia de 1 o más caracteres que no estén en blanco, entonces la respuesta es definitivamente sí, y también se hace de manera muy simple. Esto se debe [[:blank:]]*
, y [^[:blank:]]*
son complementos booleanas y - siempre todos los caracteres de una cadena están completos - [[:blank:]]*
T [^[:blank:]]*
puede describir cualquier cadena sea posible, de la misma manera .*
lo hace.
Si existe un carácter incompleto o una secuencia de bytes inválida dentro de una cadena, ninguno de los dos puede describirla correctamente de principio a fin, como a veces puede ocurrir al interpretar una cadena en la codificación incorrecta. Para garantizar un carácter completo por byte en cualquier cadena, la configuración regional de C se puede forzar como:
LC_ALL=C sed ...
... lo que evitaría cualquier problema que describa la cadena de la cabeza a la cola con un patrón todo incluido como .*
o([ ]*[^ ]*)*
Un patrón completamente complementario puede repetir tantas veces como sea necesario de izquierda a derecha la longitud de cualquier cadena para aterrizar en la última aparición posible sin interrupción en el patrón. Este es, definitivamente, un lenguaje regular.
BRE:
sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'
ANTES DE:
sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'
Ambas versiones seguirán imprimiendo líneas en blanco, y esto se debe a que la *
estrella de Kleene coincide con cero o más ocurrencias de un patrón. Primero coincide con cero o más caracteres no en blanco, luego cero o más caracteres en blanco, luego cero o más ocurrencias de las coincidencias agrupadas hasta que coincida con la cadena en su totalidad.
Una vez hecho todo esto, la magia ocurre en el reemplazo: las referencias devueltas por los grupos \1
y \2
son las últimas ocurrencias de cada uno. Entonces, cuando se realiza el reemplazo, toda la cadena se reemplaza con solo la última aparición en una línea de cero o más caracteres no en blanco, o el subgrupo \2
.
Por supuesto, esto funciona para cualquier cadena posible , incluso una vacía, lo que significa que ambos formularios imprimirán caracteres de nueva línea para líneas que contienen solo caracteres en blanco o ninguno. Para manejar esto, hay un par de cosas que puede hacer, pero primero hagamos que la clase de caracteres sea un poco más fácil de escribir:
b='[:blank:]'
Ahora, para imprimir solo si una línea contiene uno o más caracteres no en blanco, puede hacer:
BRE:
sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"
ANTES DE:
sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
- Caso BRE: la sustitución siempre se realiza y solo se imprimen los espacios de patrón con al menos un carácter restante.
- Caso ERE: la sustitución solo se intenta en un espacio de patrón que contiene al menos un carácter no en blanco.
Cualquiera de las formas funcionará con cualquiera de los métodos, siempre que la sintaxis sea correcta.
El -n
interruptor deshabilita la impresión automática del espacio del patrón, y el p
indicador de la s///
ubicación o los comandos de /
dirección /
imprime sus resultados solo si tiene éxito.
Esta misma lógica se puede aplicar para obtener cualquier {num}
ocurrencia, como:
BRE:
sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"
ANTES DE:
sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"
... donde las num
dos expresiones regulares se pueden reemplazar con un número para imprimir solo la {num}
aparición especificada de una secuencia de caracteres no en blanco. Aquí se usa una forma ligeramente diferente para garantizar que el recuento no esté sesgado para el espacio inicial en una cadena.
Tenga en cuenta que el -E
cambio ERE a sed
es compatible con las versiones BSD y GNU, aunque todavía no es la sintaxis estándar POSIX.
sed
?