La substitution de commandes peut-elle être imbriquée dans la substitution de variables?

10

Je voudrais utiliser la substitution de variable sur une chaîne particulière à laquelle j'accède via une commande. Par exemple, si je copie quelque chose dans mon presse-papiers, je peux y accéder comme ceci.

$ xclip -o -selection clipboard
Here's a string I just copied.

Si je l'assigne à une variable, alors je peux faire une substitution de variable dessus.

$ var=$(xclip -o -selection clipboard)
$ echo $var
Here's a string I just copied.
$ echo ${var/copi/knott}
Here's a string I just knotted.

Cependant, existe-t-il un moyen de faire une substitution de variable sans l'assigner à une variable? Conceptuellement, quelque chose comme ça.

$ echo ${$(xclip -o -selection clipboard)/copi/knott}
bash: ${$(xclip -o -selection clipboard)/copi/knott}: bad substitution

Cette syntaxe échoue, car vardevrait être un nom de variable, pas une chaîne.

Sparhawk
la source

Réponses:

6

Non, tu ne peux pas. bashet la plupart des autres shells (sauf zsh) ne permettent pas la substitution imbriquée.

Avec zsh, vous pouvez faire une substitution imbriquée :

$ echo ${$(echo 123)/123/456}   
456
cuonglm
la source
J'accepte cette réponse, car elle fournit des preuves circonstancielles que ce n'est pas possible en bash. (Et me pousse à nouveau vers la migration vers zsh.)
Sparhawk
2

Oui, vous pouvez le faire - en quelque sorte. Ce n'est vraiment pas joli. C'est plus comme en ligne qu'imbriqué. Le problème est que vous devez opérer sur la valeur du paramètre que vous développez - si ce paramètre n'a pas de valeur, vous ne ferez pas grand-chose. Ainsi, vous pouvez attribuer la valeur tout en la développant et ce n'est guère un raccourci.

v=; echo "${v:=${0##*["$0${v:=$(xsel -bo)}"]}${v/copi/knott}}"

J'utilise l' $0extension param dans la chaîne pour masquer l'affectation. Il affecte la valeur de la var dans une extension d'affectation imbriquée. L'extérieur a la priorité - mais comme il s'étendrait à tout ce que fait l'intérieur, c'est difficile à dire. Cependant, si nous faisons taire l'expansion intérieure, puis la modifions, vous pouvez obtenir ce que vous voulez. Après avoir copié votre chaîne dans mon presse-papiers (je n'ai pas xclip- juste xsel), elle affiche:

Here's a string I just knotted.

C'est un peu plus clair ce qui se passe si vous omettez $0, cependant:

v=; echo "${v:=${v:=$(xsel -bo)}${v/copi/knott}}"

Cela imprime:

Here's a string I just copied.  Here's a string I just knotted.

... car l'affectation interne se produit avant la modification, mais, comme indiqué, l'affectation externe a priorité - et elle s'étend à la fois à l'expansion de l'affectation interne et à l'expansion interne modifiée.

Bien sûr, rien de tout cela ne fonctionne du tout si le paramètre ciblé est déjà affecté - vous ne pouvez donc le faire sûrement que si vous videz la variable en premier lieu ... ce qui, honnêtement, est probablement le moment le plus approprié pour l'affecter après tout .

mikeserv
la source
+1 pour la solution de contournement, bien que comme vous le dites, c'est une solution de contournement probablement pire que d'assigner une variable!
Sparhawk
@Sparhawk - ouais, certainement pire. Et il n'y a vraiment rien de mal à cela de toute façon - il n'y a pas grand-chose à gagner à part l'incertitude. Vous pouvez trouver une aliasindirection pour la rendre un peu plus pratique - mais si cela en vaut la peine, vous devez configurer une fonction pour gérer les devis sécurisés et faire quelque chose avec evalou quelque chose comme ça de toute façon. w / eval- si vous pouvez rendre les premiers caractères de la quantité de sortie du sous-commande à une syntaxe d'expansion exploitable - alors vous pouvez probablement aller beaucoup plus loin beaucoup plus facilement. Je sais qu'une telle chose serait facile avec xsel- cela prend stdin - mais xsel?
mikeserv
@Sparhawk - Je sais seulement comment faire tout cela, soit dit en passant, car dans certaines situations, cela peut être utile - comme des extensions rapides ou ici-doc - dans lequel vous ne pouvez pas obtenir une affectation de shell actuelle à appliquer autrement.
mikeserv
1

Si vous ne souhaitez pas créer une variable, il existe d'autres façons d'effectuer une substitution de chaîne:

$ echo $(xclip -o -selection clipboard | sed 's/copi/knott/')
Here's a string I just knotted.
John1024
la source
Merci, je savais que je pourrais utiliser à la sedplace, mais c'était censé être plus une question générale, sur l'imbrication des substitutions.
Sparhawk
@Sparhawk À ma connaissance, on ne peut pas faire de substitution de variable sans avoir de variable.
John1024
D'accord, c'est probablement la réponse alors. Je vais laisser la question ouverte pendant quelques jours pour voir si quelqu'un d'autre a une réponse référencée, puis accepter celle-ci autrement. Merci.
Sparhawk
@Sparhawk Très bien.
John1024
+1, mais je vais accepter une autre réponse , car elle fournit des preuves circonstancielles légèrement plus concrètes qu'elle ne fonctionne pas en bash.
Sparhawk