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.

gakhov
fuente
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
hombre trabajando
fuente
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.

Stéphane Chazelas
fuente
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

usuario1678213
fuente
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.

tojrobinson
fuente
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
Ethaning
fuente