Scinde une chaîne avec zsh comme en Python
En python:
s = '1::3'
a = s.split(':')
print a[0] # '1' good
print a[1] # '' good
print a[2] # '3' good
Comment puis-je obtenir le même effet avec zsh
?
La suite de la tentative échoue:
string="1::3"
a=(${(s/:/)string})
echo $a[1] # 1
echo $a[2] # 3 ?? I want an empty string, as in Python
Vous devez vous connecter pour publier un commentaire.
La solution est d'utiliser la
@
modificateur, comme indiqué dans la zsh docs:Par ailleurs, si on a le choix du séparateur, il est beaucoup plus facile et moins sujette aux erreurs d'utiliser un retour à la ligne comme séparateur. La bonne façon de diviser les lignes avec zsh est alors:
Je ne sais pas si oui ou non les guillemets sont nécessaires ici...
/
s peut être remplacé par|
s, il me semble (par exemplea=(${(s|/|)string}")
). Je n'arrive pas à trouver toute la documentation sur ce point, cependant, de sorte que peut-être il y a quelques subtils changements de comportement.Cela fonctionne dans les deux zsh (avec
setopt shwordsplit
ouzsh -y
) et Bash (de base zéro tableaux):echo ${a[1]}
etecho ${a[3]}
et obtenir1
et3
, respectivement (indice devrait être0
et2
pour Bash). Si elle est courte, postez ici ce que vous avez essayé et exactement comment il a échoué. Si c'est un peu plus long, poser une nouvelle question et un lien vers ici.IFS=':' cmd args...
, de sorte que le changement est couplé avec le contexte/la durée de vie où il est prévu/utilisé. Alors ce n'est Pas Votre Travail pour connaître les valeurs antérieures vous ne l'utilisez pas, ou de gérer ou de recréer l'environnement extérieur, etc. - à la place, ils nettoient eux-mêmes.f(){ a=(${s}); echo "$a, $s, '$IFS'" }; IFS=':' s='1::3' f; echo "$a, $s, '$IFS'"
Les résultats sont... problématique. Les deux IFS et s sont limités à f, donc f est l'écho voit les valeurs données, et de l'autre l'écho a vide s et IFS. Pendant ce tempsa
est implicitement mondiale, de sorte que l'extérieur de l'écho obtient la valeur des
il ne peut pas voir directement. Mais la valeur est "1::3'. Je suis trop fatigué pour dire si j'ai fait une erreur stupide, des idées?$a
sorties seulement le premier élément du tableau. À l'aide de${a[@]}
sera de sortie le tableau d'ensemble. Mais à l'aide dedeclare -p
est de mieux en test car il révèle la structure des tableaux:unset a s; f(){ a=(${s}); declare -p a s IFS; }; IFS=':' s='1::3' f; declare -p a s IFS
. En outre, vous pouvez obtenir une meilleure représentation deIFS
en faisant ceci:printf '%q\n' "$IFS"
. Le processus de mise en vairiable valeurs...a
,s
et la valeur1::3
, mais le comportement de l' (corrigé) exemple pour moi est totalement comme prévu. Notez que dans un script réel, si la valeur des
est d'être utilisé en dehors de la fonction, alors il ne devrait pas être limitée à l'environnement d'exécution de la fonction et uniquement le (temporaire) attribution deIFS
serait. Donc, ...unset a; s='1::3'; f(){ a=(${s}); declare -p a s IFS; }; IFS=':' f; declare -p a s IFS
IFS=':'
, et pourtant,a=(${s})
n'a pas split s par ':'.1, 1::3, ':'
. Le1
est le premier élément du tableaua
qui est le résultat de divisers
. Voir mes commentaires précédents concernant les meilleures façons de sortie des tableaux. Quelque chose que je n'ai pas mentionné plus tôt, est à l'aide delocal IFS=':'
à l'intérieur d'une fonction permettant de limiter la portée (mais qui ne s'applique pas à votre point d'origine).echo $a
ouecho "$a"
je reçois tous les éléments, le premier élément est, peu importe comment ils sont affectés. En ajoutant le point-virgule pour mon exemple n'apparaît pas à changer quoi que ce soit (je ne sais pas pourquoi.) Oh, et f à partir de votre exemple à l'aide déclare sortiestypeset -g -a a=( 1::3 )
,export s=1::3
, etexport IFS=:
- il n'est certainement pas la séparation d' ':' comme il le prétend.@
modificateur sansIFS
(ou vous pouvez avoir besoinsetopt shwordsplit
comme je l'ai indiquer dans le mien).