División de cadena por la primera aparición de un delimitador


54

Tengo una cadena en el siguiente formato

id;some text here with possible ; inside

y desea dividirlo en 2 cadenas por primera aparición de ;. Entonces, debería ser: idysome text here with possible ; inside

Sé cómo dividir la cadena (por ejemplo, con cut -d ';' -f1), pero se dividirá en más partes ya que tengo ;dentro de la parte izquierda.


Después de dividir la cadena, ¿qué quieres hacer con el "id"? ¿Desea asignarlo a una variable, imprimirlo, etc.?
Daemon of Chaos

Voy a tener 2 variables: idystring
gakhov

Respuestas:


65

cut Suena como una herramienta adecuada para esto:

bash-4.2$ s='id;some text here with possible ; inside'

bash-4.2$ id="$( cut -d ';' -f 1 <<< "$s" )"; echo "$id"
id

bash-4.2$ string="$( cut -d ';' -f 2- <<< "$s" )"; echo "$string"
some text here with possible ; inside

Pero reades aún más adecuado:

bash-4.2$ IFS=';' read -r id string <<< "$s"

bash-4.2$ echo "$id"
id

bash-4.2$ echo "$string"
some text here with possible ; inside

3
¡Excelente! ¡Funciona a las mil maravillas! Seleccionaré el readpuesto que estoy usando bash. Gracias @manatwork!
gakhov

El cutenfoque solo funcionará cuando "$ s" no contenga caracteres de nueva línea. leer está en cualquier shell similar a Bourne. <<< está en rc, zsh y versiones recientes de bash y ksh93 y es el que no es estándar.
Stéphane Chazelas

Vaya, tienes razón @StephaneChazelas. Mi mente estaba en -aalguna razón al mencionar bashla de read. (Evidentemente no sirve de nada aquí)
Manatwork

Olvidé mencionar que el enfoque de lectura no funciona si $ s contiene caracteres de nueva línea tampoco. He añadido mi propia respuesta.
Stéphane Chazelas

1
Me gustaría enfatizar el guión final -f 2-en el string="$( cut -d ';' -f 2- <<< "$s" )"; echo "$string"comando. Esto es lo que ignora el resto de los delimitadores en la cadena para la impresión. No es evidente cuando se mira en la página del manual decut
Steen

18

Con cualquier estándar sh (incluyendo bash):

sep=';'
case $s in
  (*"$sep"*)
    before=${s%%"$sep"*}
    after=${s#*"$sep"}
    ;;
  (*)
    before=$s
    after=
    ;;
esac

readlas soluciones basadas funcionarían para valores de un solo carácter (y con algunos shells, de un solo byte) $sepdistintos de espacio, tabulación o nueva línea y solo si $sno contienen caracteres de nueva línea.

cutLas soluciones basadas solo funcionarían si $sno contienen caracteres de nueva línea.

sedpodrían idearse soluciones que manejen todos los casos de esquina con cualquier valor de $sep, pero no vale la pena ir tan lejos cuando hay soporte incorporado en el shell para eso.


6

Como mencionó que desea asignar los valores a id y string

primero asigne su patrón a una variable (digamos str)

    str='id;some text here with possible ; inside'
    id=${str%%;} 
    string=${str#;}

Ahora tienes tus valores en las variables respectivas


si obtiene su patrón de un comando, use set - some_command, entonces su patrón se almacenará en $ 1 y usará el código anterior con 1 en lugar de str
user1678213

1
¿En qué se diferencia esta respuesta de @StephaneChazelas?
Bernhard

4

Además de las otras soluciones, puede probar algo regexbasado:

a="$(sed 's/;.*//' <<< "$s")"
b="$(sed 's/^[^;]*;//' <<< "$s")"

o dependiendo de lo que intente hacer exactamente, podría usar

sed -r 's/^([^;]*);(.*)/\1 ADD THIS TEXT BETWEEN YOUR STRINGS \2/'

dónde \1y \2contener las dos subcadenas que estabas deseando.


1

Solución en bash estándar:

    text='id;some text here with possible ; inside'
    text2=${text#*;}
    text1=${text%"$text2"}

    echo $text1
    #=> id;
    echo $text2
    #=> some text here with possible ; insideDD
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.