
La cadena original es así:
str-str001-002_01
str-str005-006_05
Me gustaría extraer la cadena antes del número y después del guión bajo, por lo que sería así:
str-str_01
str-str_05
Recuerdo que sed podía separar el patrón en grupos como este:
sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\1\3/p'
pero imprime:
str-str0002_01
Luego recuerdo que [0-9] es solo un número, así que lo probé con el signo + o *. Entonces da un resultado vacío.
pd: usando
echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\2/p'
Puedo ver que coincide 1-0
.
Luego lo probé con:
echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]\+-[0-9]\+\)\(.*$\)/\2/p'
dejo los primeros 2 numeros, y solo coincide
1-002
Entonces, ¿cómo hacer que coincida?001-002
Respuesta1
Esto proporciona el resultado requerido:
sed -nE 's/^([^0-9]*).*_([^_]+)$/\1_\2/p'
Salida de su ejemplo
str-str_01
str-str_05
Explicación
sed -nE 's/…/…/p'
- Utilice ERE, no imprima líneas a menos que coincidan^
- anclar al inicio de la línea([^0-9]*)
- coincidir con un patrón lo más largo posible, es decir, al menos un carácter que no sea un dígito.*_
- coincidir tanto como sea posible (sin incluir nada), seguido de "_
"([^_]+)
- hacer coincidir un patrón lo más largo posible (al menos un carácter) que no sea un guión bajo$
- anclar hasta el final de la línea\1_\2
- reemplazar toda la línea con la primera(…)
coincidencia, "_
", y la segunda(…)
coincidencia
La razón por la que sus intentos no funcionaron como esperaba es porque *
(y +
) es codicioso: consumirá tantos caracteres como sea posible que coincidan con el átomo anterior. Entonces, para un ERE de (.*)([0-9]+)
aplicado a algo como abc123
, se .*
consumirá abc12
, dejando [0-9]+
que coincida solo 3
. Necesitarías un "no dígito" para limitar el primer partido: ([^0-9]*)([0-9]+)
obtener abc
y 123
.
Respuesta2
$ cat file
str-str001-002_01
str-str005-006_05
$ sed 's/[0-9]\{3\}-[0-9]\{3\}//' file
str-str_01
str-str_05
El comando de sustitución aquí es hacer coincidir y eliminar NNN-NNN
donde NNN
hay una serie de tres dígitos.
para igualaral menos unodígito, utilizar 1,
en lugar de 3
:
$ sed 's/[0-9]\{1,\}-[0-9]\{1,\}//' file
str-str_01
str-str_05
Esto corresponde al uso +
en una expresión regular extendida. Las expresiones regulares utilizadas de sed
forma predeterminada son expresiones regulares "básicas" y +
coincidirían con un carácter más literal. La mayoría de sed
las implementaciones también admiten expresiones extendidas con -E
:
$ sed -E 's/[0-9]+-[0-9]+//' file
str-str_01
str-str_05
Usar *
, como en [0-9]*-[0-9]*
, no funcionaría ya que coincidiría con el guión str-str
(que tiene cero dígitos a su alrededor).
Si sientes que realmente tienes que hacer coincidir toda la línea y capturar las partes que deseas conservar, entonces también puedes hacerlo. El siguiente comando captura los no dígitos iniciales y el bit final, incluido el guión bajo:
$ sed 's/\([^0-9]*\).*\(_.*\)/\1\2/' file
str-str_01
str-str_05
Esto, sin embargo, en mi humilde opinión es un poco difícil de descifrar y hace suposiciones sobre el inicio y el final de la cadena que nunca mencionaste en la pregunta. El inicio no puede, por ejemplo, contener dígitos antes de los dígitos que desea eliminar, y el final de la cadena se cortará en elúltimoguión bajo, no necesariamente después de los dígitos que desea eliminar si hay varios guiones bajos en esa parte de la cadena.
Siempre puedes agregar más a esta expresión para asegurarte de que NNN-NNN
no se capture solo el bit, pero eso haría aún más difícil entender la expresión.