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.