Je pense que vous demandez deux choses différentes.
Existe-t-il un moyen de faire bash imprimer ces informations sans la boucle?
Oui, mais ils ne sont pas aussi efficaces que l'utilisation de la boucle.
Existe-t-il un moyen plus propre d'obtenir / imprimer uniquement la partie clé = valeur de la sortie?
Oui, la for
boucle. Il a l'avantage de ne pas nécessiter de programmes externes, est simple et facilite le contrôle du format de sortie exact sans surprise.
Toute solution qui essaie de gérer la sortie de declare -p
( typeset -p
) doit faire face à a) la possibilité que les variables elles-mêmes contiennent des parenthèses ou des crochets, b) la citation qui declare -p
doit être ajoutée pour que sa sortie soit valide pour le shell.
Par exemple, votre expansion b="${a##*(}"
mange certaines des valeurs, si une clé / valeur contient une parenthèse ouvrante. En effet, vous avez utilisé ##
, ce qui supprime le préfixe le plus long . Pareil pour c="${b%% )*}"
. Bien que vous puissiez bien sûr faire correspondre declare
plus exactement le passe-partout imprimé , vous auriez encore du mal si vous ne vouliez pas tous les devis.
Cela n'a pas l'air très agréable sauf si vous en avez besoin.
$ declare -A array=([abc]="'foobar'" [def]='"foo bar"')
$ declare -p array
declare -A array='([def]="\"foo bar\"" [abc]="'\''foobar'\''" )'
Avec la for
boucle, il est plus facile de choisir le format de sortie comme vous le souhaitez:
# without quoting
$ for x in "${!array[@]}"; do printf "[%s]=%s\n" "$x" "${array[$x]}" ; done
[def]="foo bar"
[abc]='foobar'
# with quoting
$ for x in "${!array[@]}"; do printf "[%q]=%q\n" "$x" "${array[$x]}" ; done
[def]=\"foo\ bar\"
[abc]=\'foobar\'
À partir de là, il est également simple de changer le format de sortie sinon (supprimez les crochets autour de la clé, mettez toutes les paires clé / valeur sur une seule ligne ...). Si vous avez besoin de citer autre chose que le shell lui-même, vous devrez toujours le faire vous-même, mais au moins vous avez les données brutes sur lesquelles travailler. (Si vous avez des sauts de ligne dans les clés ou les valeurs, vous aurez probablement besoin de quelques citations.)
Avec un Bash actuel (4.4, je pense), vous pouvez également utiliser à la printf "[%s]=%s" "${x@Q}" "${array[$x]@Q}"
place de printf "%q=%q"
. Il produit un format cité un peu plus agréable, mais est bien sûr un peu plus de travail à retenir pour écrire. (Et il cite le cas du coin de la @
clé de tableau, qui %q
ne cite pas.)
Si la boucle for semble trop fatiguée pour être écrite, enregistrez-la quelque part (sans citer ici):
printarr() { declare -n __p="$1"; for k in "${!__p[@]}"; do printf "%s=%s\n" "$k" "${__p[$k]}" ; done ; }
Et puis il suffit de l'utiliser:
$ declare -A a=([a]=123 [b]="foo bar" [c]="(blah)")
$ printarr a
a=123
b=foo bar
c=(blah)
Fonctionne également avec les tableaux indexés:
$ b=(abba acdc)
$ printarr b
0=abba
1=acdc
printf ...%q...
variante ne convient pas pour une réintroduction dans le shell si le tableau a une@
clé car% q ne la cite pas eta=([@]=value)
est une erreur de syntaxe dansbash
."${x@Q}"
cite cela aussi, car il cite toutes les chaînes (et semble plus joli). ajouté une note sur l'utilisation de cela.zsh
avec ses indicateurs d'expansion variables (qui sont encore antérieurs aux bash par décennies et avec lesquels vous pouvez choisir le style de citation: $ {(q) var}, $ {(qq) var} ...) pour une meilleure conception. bash a le même problème que mksh en ce qu'il ne cite pas la chaîne vide (pas un problème ici car de toute façon bash ne prend pas en charge les clés vides). De plus, lorsque vous utilisez des styles de guillemets autres que des guillemets simples (${var@Q}
recourt à$'...'
pour certaines valeurs), il est important que le code soit réintroduit dans les mêmes paramètres régionaux.x=; echo "${x@Q}"
ne donne''
,unset x; echo "${x@Q}"
ne donne rien.) Bash@Q
semble préférer$'\n'
une nouvelle ligne littérale, qui peut en fait être bonne dans certaines situations (mais je ne peux pas dire ce que d'autres préfèrent). Bien sûr, avoir le choix ne serait pas mauvais.$'...'
syntaxe est un problème potentiel dans des choses comme lesLC_ALL=zh_HK.big5hkscs bash -c 'a=$'\''\n\u3b1'\''; printf "%s\n" "${a@Q}"'
sorties$'\n<0xa3><0x5c>'
et0x5c
seule la barre oblique inverse, vous auriez donc un problème si cette citation était interprétée dans un environnement local différent.2 fourchettes
Peut être ça:
3 fourchettes
ou ca:
Pas de fourchette
être comparé à
Comparaison des temps d'exécution
Comme la dernière syntaxe n'utilise pas de fork, elles pourraient être plus rapides:
Mais cette affirmation ne reste pas vraie si le tableau devient grand; si la réduction des fourches est efficace pour les petits processus, l'utilisation d'outils dédiés est plus efficace pour les processus plus importants.
Remarque
Comme les deux solutions ( fourchues ) utilisent l' alignement , aucune d'entre elles ne fonctionnera si une variable contient une nouvelle ligne . Dans ce cas, le seul moyen est une
for
boucle.la source
for
. Ce qui est vraiment dommage.pr
est plus courte ... Je ne suis pas sûr que lapr
syntaxe reste plus lente, même avec de grands tableaux!${!array[@]}
et d'${array[@]}
abord pour que cela fonctionne.paste
est plus long que lafor
boucle de la question écrite sur une lignefor i in "${!array[@]}"; do echo "$i=${array[$i]}" ; done
, mais nécessite deux sous-coquilles et un programme externe. Comment est-ce plus propre? La solution avecpr
casse également s'il y a beaucoup d'éléments, car elle essaie de paginer la sortie. Vous auriez besoin d'utiliser quelque chose comme| pr -2t -l"${#array[@]}"
qui commence à devenir difficile à retenir par rapport à la boucle simple, et encore une fois, c'est plus long que cela.bash
,cmd1 | cmd2
signifie 2 fourches, même si cmd1 ou cmd2 ou les deux sont intégrés.Si vous recherchez un shell avec une meilleure prise en charge des tableaux associatifs, essayez
zsh
.Dans
zsh
(où des tableaux associatifs ont été ajoutés en 1998, par rapport à 1993 pour ksh93 et 2009 pour bash),$var
ou se${(v)var}
développe aux valeurs (non vides) du hachage,${(k)var}
aux clés (non vides) (dans le même ordre), et${(kv)var}
aux clés et valeurs.Pour conserver les valeurs vides, comme pour les tableaux, vous devez citer et utiliser l'
@
indicateur.Donc, pour imprimer les clés et les valeurs, c'est juste une question de
Bien que pour tenir compte d'un hachage éventuellement vide, vous devez faire:
Notez également que zsh utilise une syntaxe de définition de tableau beaucoup plus sensible et utile que celle
ksh93
(copiée parbash
):Ce qui facilite grandement la copie ou la fusion de tableaux associatifs:
(vous ne pouvez pas facilement copier un hachage sans boucle avec
bash
, et notez quebash
actuellement ne prend pas en charge les clés vides ou les clés / valeurs avec des octets NUL).Voir également les
zsh
fonctionnalités de compression de tableau dont vous aurez généralement besoin pour travailler avec des tableaux associatifs:la source
Puisque la composition fait ce que vous voulez, pourquoi ne pas simplement éditer sa sortie?
donne
Où
Verbose mais il est assez facile de voir comment fonctionne le formatage: il suffit d'exécuter le pipeline avec progressivement plus de commandes sed et tr . Modifiez-les pour convenir à de jolis goûts d'impression.
la source
sed
s ettr
n'est pas encore plus simple qu'unfor
boucle avecprintf
.tr
traduire caractère par caractère, cela ne correspond pas aux chaînes?tr "]=" " ="
change "]" en espace et=
en en=
, quelle que soit la position. Vous pourriez donc probablement combiner les troistr
à un.Une autre option consiste à répertorier toutes les variables et grep pour celle que vous souhaitez.
set | grep -e '^aa='
J'utilise cela pour le débogage. Je doute qu'il soit très performant puisqu'il répertorie toutes les variables.
Si vous faisiez cela souvent, vous pourriez en faire une fonction comme celle-ci:
aap() { set | grep -e "^$1="; }
Malheureusement, lorsque nous vérifions les performances en utilisant le temps:
$ time aap aa aa=([0]="abc") . real 0m0.014s user 0m0.003s sys 0m0.006s
Par conséquent, si vous faisiez cela très souvent, vous voudriez la version NO FORKS de @ F.Hauri car elle est tellement plus rapide.
la source