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.

Gakhov
la source
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
homme au travail
la source
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.

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

utilisateur1678213
la source
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/'

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

tojrobinson
la source
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
ethaning
la source