Fractionner une chaîne par la première occurrence d'un délimiteur


54

J'ai une ficelle au format suivant

id;some text here with possible ; inside

et voulez le scinder en 2 chaînes par la première occurrence de la ;. Donc, ça devrait être: idetsome text here with possible ; inside

Je sais comment scinder la chaîne (avec, par exemple cut -d ';' -f1), mais elle se divisera en plusieurs parties puisque j'ai ;la partie gauche.


Après la division de la chaîne, que voulez-vous faire avec "id"? Voulez-vous l'affecter à une variable, l'imprimer, etc.?
— Daemon of Chaos

Je vais avoir 2 variables: idetstring
— gakhov

Réponses:


65

cut sonne comme un outil approprié pour cela:

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

Mais readest encore plus approprié:

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
Génial! Il fonctionne comme un charme! Je vais sélectionner le readdepuis que j'utilise bash. Merci @ Manatwork!
— Gakhov

L' cutapproche ne fonctionnera que si "$ s" ne contient pas de caractères de nouvelle ligne. lu est dans n'importe quel shell Bourne-like. <<< est dans les versions rc, zsh et récente de bash et ksh93 et ​​est celui qui n'est pas standard.
— Stéphane Chazelas

Oups, vous avez raison @StephaneChazelas. Mon esprit était -apour une raison quelconque en mentionnant bash« s read. (Évidemment d'aucune utilité ici.)
— manatwork

J'ai oublié de mentionner que l'approche de lecture ne fonctionne pas si $ s contient des caractères de nouvelle ligne. J'ai ajouté ma propre réponse.
— Stéphane Chazelas

1
Je voudrais souligner le tiret final -f 2-dans la string="$( cut -d ';' -f 2- <<< "$s" )"; echo "$string"commande. C'est ce qui ignore le reste des délimiteurs dans la chaîne pour l'impression. Pas évident quand on regarde la page de manuel decut
— Steen

18

Avec n'importe quel sh standard (bash compris):

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

readles solutions basées fonctionneraient pour des caractères uniques (et avec certains shells, un octet), des valeurs $sepautres que espace, tabulation ou nouvelle ligne et uniquement si elles $sne contiennent pas de caractères de nouvelle ligne.

cutles solutions basées ne fonctionneraient que si elles $sne contenaient pas de caractères de nouvelle ligne.

seddes solutions pourraient être conçues pour traiter tous les cas $sepcritiques avec une valeur quelconque , mais cela ne vaut pas la peine d'aller aussi loin quand il y a un support intégré dans le shell pour cela.


6

Comme vous l'avez dit, vous voulez affecter les valeurs à id et string

assignez d'abord votre motif à une variable (disons str)

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

Maintenant, vous avez vos valeurs dans les variables respectives


si vous obtenez votre modèle à partir d'une commande, utilisez set - some_command, votre modèle sera alors stocké dans $ 1 et utilisera le code ci-dessus avec 1 au lieu de str
— user1678213

1
En quoi cette réponse est-elle différente de @StephaneChazelas?
— Bernhard

4

En plus des autres solutions, vous pouvez essayer une solution regex:

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

ou selon ce que vous essayez de faire exactement, vous pouvez utiliser

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

où \1et \2contiennent les deux sous-chaînes que vous vouliez.


1

Solution en bash standard:

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

    echo $text1
    #=> id;
    echo $text2
    #=> some text here with possible ; insideDD
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.