¿Se puede anidar la sustitución de comandos en la sustitución de variables?

10

Me gustaría usar la sustitución de variables en una cadena particular a la que accedo mediante un comando. Por ejemplo, si copio algo en mi portapapeles, puedo acceder a él de esta manera.

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

Si lo asigno a una variable, entonces puedo hacer una sustitución de variables en él.

$ 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.

Sin embargo, ¿hay alguna forma de hacer una sustitución de variables sin asignarla a una variable? Conceptualmente, algo como esto.

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

Esta sintaxis falla, porque vardebería ser un nombre de variable, no una cadena.

Gavilán
fuente

Respuestas:

6

No puedes. bashy la mayoría de los otros shells (excepto zsh) no permiten la sustitución anidada.

Con zsh, puedes hacer una sustitución anidada :

$ echo ${$(echo 123)/123/456}   
456
Cuonglm
fuente
Aceptaré esta respuesta, ya que proporciona alguna evidencia circunstancial de que no es posible bash. (Y me empuja nuevamente hacia la migración zsh).
Sparhawk
2

Sí, puedes hacer eso, más o menos. Realmente no es bonito. Es más como en línea que anidado. El problema es que tiene que operar sobre el valor del parámetro que expande; si ese parámetro no tiene valor, entonces no hará mucho. Por lo tanto, puede asignar el valor mientras lo expande y apenas es un atajo.

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

Utilizo la $0expansión param dentro de la cadena para ocultar la tarea. Asigna el valor de var dentro de una expansión de asignación anidada. Lo externo tiene prioridad, pero debido a que simplemente se expandiría a lo que sea que haga el interno, es difícil saberlo. Sin embargo, si silenciamos la expansión interna, luego modifíquela, puede obtener lo que desea. Después de copiar su cadena en mi portapapeles (no tengo xclip, solo xsel) imprime:

Here's a string I just knotted.

Sin $0embargo, es un poco más claro lo que sucede si lo dejas afuera:

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

Que imprime:

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

... porque la asignación interna ocurre antes de la modificación, pero, como se señaló, la asignación externa tiene prioridad, y se expande tanto a la expansión de la asignación interna como a la expansión interna modificada.

Por supuesto, nada de eso funciona si el parámetro objetivo ya está asignado, por lo que solo puede hacerlo con seguridad si vacía la variable en primer lugar ... lo que, sinceramente, es probablemente el momento más conveniente para asignarlo después de todo .

mikeserv
fuente
¡+1 para la solución alternativa, aunque como usted dice, es una solución que probablemente sea peor que asignar una variable!
Sparhawk
@Sparhawk: sí, definitivamente peor. Y de todos modos no hay nada de malo en eso: no hay mucho que ganar, excepto la incertidumbre. Podría crear alguna aliasindirecta para hacerlo un poco más conveniente, pero si vale la pena, entonces debe configurar una función para manejar las cotizaciones seguras y hacer algo con evalalgo similar de todos modos. w / eval- si puede hacer que los primeros caracteres de la cantidad de salida del subcomando se conviertan en una sintaxis de expansión factible, entonces probablemente pueda avanzar mucho más fácilmente. Sé que tal cosa sería fácil con xsel- requiere stdin - pero xsel?
mikeserv
@Sparhawk: por cierto, solo sé cómo hacer algo de eso, porque en algunas situaciones puede ser útil, como expansiones rápidas o here-doc, en las que no puedes obtener una asignación de shell actual para aplicar de otra manera.
mikeserv
1

Si no desea crear una variable, existen otras formas de realizar la sustitución de cadenas:

$ echo $(xclip -o -selection clipboard | sed 's/copi/knott/')
Here's a string I just knotted.
John1024
fuente
Gracias, sabía que podría usarlo seden su lugar, pero estaba destinado a ser una pregunta más general, sobre la anidación de sustituciones.
Sparhawk
@Sparhawk Que yo sepa, uno no puede hacer la sustitución de variables sin tener una variable.
John1024
Bien, esa es probablemente la respuesta entonces. Dejaré la pregunta abierta durante unos días para ver si alguien más tiene una respuesta referenciada, luego acepte esta de lo contrario. Gracias.
Sparhawk
@Sparhawk Muy bien.
John1024
+1, pero voy a aceptar otra respuesta , ya que proporciona evidencia circunstancial un poco más concreta de que no funciona en bash.
Sparhawk