¿Cómo 'soltar' / eliminar caracteres frente a una cadena?

13

Tengo una cadena que me gustaría manipular. La cadena es H08W2345678¿cómo podría manipularla para que la salida sea justa W2345678?

Del mismo modo, si quisiera eliminar los últimos 4 caracteres H08W2345678para obtener H08W234cómo hacerlo

3kstc
fuente
1
Hay muchas formas de manipular cadenas. ¿Hay alguna razón específica para usar sed?
don_crissti
@don_crissti Sin razón, aparte de la falta de experiencia. Cualquier alternativa es bienvenida ...
3kstc
@don_crissti, la historia: de un archivo CSV filtrado, tomo uno de los parámetros de una línea que es H08W2345678y necesito manipularlo. W2345678Este valor con otro dato se colocará en un correo electrónico enviado. El correo electrónico se realizará con cron.
3kstc
@don_crisstiing awkit. Creo una matriz y luego modifico cada uno de los elementos dentro de la matriz (todo de manera diferente, es decir, cambio la marca de tiempo de Epoch en segundos a una fecha, etc.)
3kstc
2
Puedes hacer cosas así con awk:printf %s\\n "XX,H08W2345678,YY" | awk -F, '{print substr($2, 4); print substr($2, 1, length($2)-4)}'
don_crissti

Respuestas:

19

Simplemente usando bash (o de ksh93dónde viene esa sintaxis o zsh):

string="H08W2345678"

echo "${string:3}"
W2345678

echo "${string:0:-4}"
H08W234

Vea el wiki de Wooledge para más información sobre la manipulación de cuerdas .

jasonwryan
fuente
Esto requiere bash 4.2 o superior. Consulte esta copia anterior del Manual de referencia de Bash, Sección 3.5.3, '' Expansión del parámetro Shell '' o la respuesta de los pollitos aquí para ver la restricción anterior ("la longitud debe evaluarse a un número mayor o igual a cero"); ... (Continúa)
Scott
(Cont.) ... vea los cambios de Bash (en Bash Hackers Wiki) (desplácese hasta la parte inferior de la sección) o noticias de bash en la organización de Servicios de Infraestructura Tecnológica en la Universidad Case Western Reserve (busque "agregado a bash-4.2" y luego desplácese hacia abajo hasta "q") para ver la revisión. ... ... ... ...  "${string:0:${#string}-4}" funciona en bash versión 4.1 siempre que la longitud $stringsea ​​de al menos 4.
Scott
PD: Esto también se ahogará con cadenas como abc-e, donde, cuando sueltas los primeros tres caracteres, te quedan -e(porque echo -eno hace lo que quieres).
Scott
8
$ echo "H08W2345678" | sed 's/^.\{3\}//'
W2345678

sed 's/^.\{3\}//'encontrará los primeros tres caracteres ^.\{3\}y los reemplazará con espacios en blanco. Aquí ^.coincidirá con cualquier carácter al comienzo de la cadena ( ^indica el inicio de la cadena) y \{3\}coincidirá con el patrón anterior exactamente 3 veces. Entonces, ^.\{3\}coincidirá con los primeros tres caracteres.

$ echo "H08W2345678" | sed 's/.\{4\}$//'
H08W234

Del mismo modo, sed 's/.\{4\}$//'reemplazará los últimos cuatro caracteres con espacios en blanco ( $indica el final de la cadena).

heemayl
fuente
1
¿Podría explicar por favor 's/^.\{3\}//'y 's/.\{4\}$//'como todavía estoy aprendiendo sed, muchas gracias
3kstc
@ 3kstc: compruebe las ediciones
heemayl
1
Por unos pocos caracteres, que haría uso ...en lugar de .\{3\}desde (a mí) que es más fácil de leer: sed -e 's/^...//' -e 's/....$//' o en una sola expresión con la alternancia: sed -r 's/^...|....$//g'. Si hubiera más de unos pocos caracteres para eliminar, entonces usaría la /.\{17}\/expresión en lugar de /.............../.
Johnny
Esto se comportará mal si la cadena es -eo -n. Por supuesto, el significado de “soltar los 4 últimos caracteres” no está definida para una cadena de menos de 4 caracteres, pero, si alguien quería adaptar esta a caer la primera o la última de un carácter, que podría explotar.
Scott
2

Si tiene un archivo en el que cada línea es una cadena de once caracteres (o lo que sea) que desea cortar, sedes la herramienta que debe utilizar. Está bien para manipular una sola cadena, pero es exagerado. Para una sola cadena, la respuesta de Jason es probablemente la mejor, si tiene acceso a bash versión 4.2 o superior. Sin embargo, las sintaxis y parecen ser exclusivas de bash (bueno, bash, ksh93, mksh y zsh). No las veo en The Open Group Base Especificaciones para Shell Command Language . Si está atascado con un shell compatible con POSIX que no admite la expansión (extracción) de subcadenas, puede usar${parameter:offset}${parameter:offset:length}

$ printf "%s\n" "${string#???}"
W2345678

$ printf "%s\n" "${string%????}"
H08W234

usando en printflugar de echoproteger contra cadenas como abc-e, donde, cuando sueltas los primeros tres caracteres, te quedan -e (y echo -eno haces lo que quieres).

Y, si no está utilizando un shell de la familia Bourne (o si está utilizando un antiguo sistema anterior a POSIX), estos deberían funcionar:

$ expr " $string" : ' ...\(.*\)'
W2345678

$ expr " $string" : ' \(.*\)....'
H08W234

El espacio inicial adicional es para evitar problemas con los valores $string que son exproperadores reales (p. Ej +.  /,  indexU match) u opciones (p. Ej.  --, --help--version).

Scott
fuente
@ Stéphane Chazelas: (1) Gracias por recordarme una trampa que conocí hace 40 años y que de alguna manera logré olvidar. (2) Siempre solía resolver esto con X; por ejemplo, expr "X$string" : 'X...\(.*\)'. OMI, eso es más fácil de leer y entender. ¿Hay algún problema con eso, o alguna razón para preferir un espacio? (3) Hoy aprendí que expr + "$string" : '...\(.*\)'ahora funciona. No recuerdo eso de hace 40 años; ¿se usa lo suficientemente ampliamente como para ser seguro recomendar? (4) Te perdiste una nota sobre la respuesta de jasonwryan y un error en la respuesta de heemayl.
Scott
AFAIK, eso expr +es solo GNU (no funcionará en Solaris ni FreeBSD AFAICS). Uso el espacio en lugar de x, ya que es menos probable que alguna exprimplementación tenga operadores que comiencen con el espacio que con xy también porque es menos probable que haya elementos de clasificación que comiencen con el espacio que con x. Pero luego me doy cuenta de que probablemente no sea una buena opción para la expr " $a" "<" " $b"comparación de cadenas, ya que algunas implementaciones terminan haciendo una comparación numérica cuando $a/ $bparecen números. Quizás expr "@@$a"...o expr "x $a"podría ser más seguro.
Stéphane Chazelas
0

Con:

string="H08W2345678"

Hacer coincidir 3 o 4 caracteres parece simple (para la mayoría de los shells):

$ printf '%s\t%s\n' "${string#???}" "${string%????}"
W2345678      H08W234

Para los shells más antiguos (como el shell Bourne), use:

$ string=H08W2345678

$ expr " ${string}" : " ...\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\)...." '
H08W234

Si se necesita un recuento numérico de caracteres, use:

$ expr " ${string}" : " .\{3\}\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\).\{4\}" '
H08W234

Por supuesto, esas expresiones regulares también funcionan con sed, awk y bash 3.0+:

$ echo "$string" | sed 's/^.\{3\}//'
W2345678

$ echo "$string" | sed 's/.\{4\}$//'
H08W234

$ echo "$string" | awk '{sub(/^.{3}/,"")}1'
W2345678

$ echo "$string" | awk '{sub(/.{4}$/,"")}1'
H08W234

$ r='^.{3}(.*)$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
W2345678

$ r='^(.*).{4}$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
H08W234
NotAnUnixNazi
fuente
-1

¿Cómo 'soltar' / eliminar caracteres frente a una cadena?

Tengo una cadena que me gustaría manipular. La cadena es H08W2345678, ¿cómo podría manipularla para que la salida sea solo W2345678?

echo "H08W2345678" | cut -c 4-
aexl
fuente
Esto solo responde a la mitad de la pregunta.
Kusalananda
Creo que tu voto negativo es injusto. Esta mitad responde la pregunta que tenía cuando busqué en Google posix eliminar los primeros caracteres y esta página apareció en los resultados de búsqueda. Además, el título de esta página cubre solo la mitad exacta de la pregunta. Regresé y contribuí cuando encontré la solución que me gustó, creo que para ese trabajo cutes mucho más elegante que cualquier otra cosa en esta página.
aexl