J'ai écrit un exemple de script pour diviser la chaîne, mais cela ne fonctionne pas comme prévu
#!/bin/bash
IN="One-XX-X-17.0.0"
IFS='-' read -r -a ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
echo "Element:$i"
done
#split 17.0.0 into NUM
IFS='.' read -a array <<<${ADDR[3]};
for element in "${array[@]}"
do
echo "Num:$element"
done
production
One
XX
X
17.0.0
17 0 0
mais je m'attendais à ce que la sortie soit:
One
XX
X
17.0.0
17
0
0
bash
shell-script
lfs
user112232
la source
la source
Réponses:
Fix, (voir aussi la réponse de S. Chazelas pour le fond), avec une sortie sensible:
Production:
Remarques:
Il vaut mieux mettre la 2ème boucle conditionnelle dans la 1ère boucle.
bash
substitution de motifs ("${i//.}"
) vérifie s'il y a un.
dans un élément. (Unecase
déclaration pourrait être plus simple, quoique moins similaire au code OP .)read
en$array
entrant<<< "${ADDR[3]}"
est moins générale que<<< "$i"
. Cela évite d'avoir à savoir quel élément a le par.
.Le code suppose que l'impression de " Element: 17.0.0 " n'est pas intentionnelle. Si ce comportement est voulu, remplacez la boucle principale par:
la source
case $i in (*.*) ...
serait un moyen plus canonique de vérifier que$i
contient.
(et aussi portable poursh
). Si vous aimez les kshismes, voir aussi:[[ $i = *.* ]]
case
dans les notes à la fin, mais nous sommes d'accord. (Puisque l'OP utilise à la fois les tableaux<<<
et les tableaux , ce n'est pas vraiment unesh
question.)Dans les anciennes versions,
bash
vous deviez citer des variables après<<<
. Cela a été corrigé dans 4.4. Dans les anciennes versions, la variable était divisée sur IFS et les mots résultants joints dans l'espace avant d'être stockés dans le fichier temporaire qui constitue cette<<<
redirection.En 4.2 et avant, lors de la redirection de buildins comme
read
oucommand
, ce fractionnement prendrait même l'IFS pour ce builtin (4.3 corrigé cela):Celui-ci corrigé en 4.3:
Mais il
$a
est toujours sujet à la division des mots:En 4.4:
Pour la portabilité vers les anciennes versions, citez votre variable (ou utilisez d'
zsh
où cela<<<
vient en premier lieu et qui n'a pas ce problème)Notez que cette approche pour diviser une chaîne ne fonctionne que pour les chaînes qui ne contiennent pas de caractères de nouvelle ligne. Notez également que
a..b.c.
serait divisé en"a"
,""
,"b"
,"c"
(pas vide dernier élément).Pour diviser des chaînes arbitraires, vous pouvez utiliser l'opérateur split + glob à la place (ce qui le rendrait standard et éviterait de stocker le contenu d'une variable dans un fichier temporaire comme le
<<<
fait):ou:
Il
''
s'agit de conserver un élément vide de fin le cas échéant. Cela diviserait également un vide$var
en un élément vide.Ou utilisez un shell avec un opérateur de fractionnement approprié:
zsh
:rc
:fish
la source
Avec awk, cela vous coûterait une ligne:
-F'[-.]'
- séparateur de champs basé sur plusieurs caractères, dans notre cas-
et.
Le résultat:
la source
IFS=-. read -r a array <<< "$IN"
Voici mon chemin:
résultat comme prévu:
la source
$IN
appelle l'opérateur split + glob. Ici, vous ne voulez pas la partie glob (essayezIN=*-*-/*-17.0.0
par exemple), donc vous devriez le faireset -o noglob
avant de l'invoquer. Voir ma réponse pour plus de détails.IFS
et de le définir globalement. Vous ne voulez vraiment changer que la valeur deIFS
quand$IN
est développé, et vous ne voulez pas non plus que l'expansion du nom de chemin soit effectuée sur l'expansion. En outre,OIFS=$IFS
ne fait pas de distinction entre les cas où aIFS
été défini sur une chaîne vide et lorsqu'ilIFS
n'a pas été complètement défini.