A substituição de comandos pode ser aninhada na substituição de variáveis?

10

Eu gostaria de usar a substituição de variável em uma sequência específica que eu acesso através de um comando. Por exemplo, se eu copiar algo para a minha área de transferência, posso acessá-lo assim.

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

Se eu atribuí-lo a uma variável, então posso fazer a substituição da variável.

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

No entanto, existe uma maneira de fazer a substituição de variáveis ​​sem atribuí-la a uma variável? Conceitualmente, algo assim.

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

Essa sintaxe falha, porque vardeve ser um nome de variável, não uma sequência.

Sparhawk
fonte

Respostas:

6

Não, você não pode. bashe a maioria dos outros shells (exceto zsh) não permite substituição aninhada.

Com zsh, você pode fazer a substituição aninhada :

$ echo ${$(echo 123)/123/456}   
456
cuonglm
fonte
Aceitarei esta resposta, pois fornece algumas evidências circunstanciais de que não é possível bash. (E me empurra de novo para migrar para zsh.)
Sparhawk
2

Sim, você pode fazer isso - mais ou menos. Realmente não é bonito. É mais como alinhado do que aninhado. O problema é que você precisa operar com o valor do parâmetro expandido - se esse parâmetro não tiver valor, você não fará muito. Portanto, você pode atribuir o valor enquanto o expande e dificilmente é um atalho.

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

Eu uso a $0expansão de parâmetros dentro da cadeia para ocultar a atribuição. Ele atribui o valor do var dentro de uma expansão de atribuição aninhada. O exterior tem precedência - mas, como seria expandido para o que o interior faz, é difícil dizer. No entanto, se silenciarmos a expansão interna, modificá-la, você poderá obter o que deseja. Depois de copiar sua string para a minha área de transferência (não tenho xclip- apenas xsel), ela é impressa:

Here's a string I just knotted.

É um pouco mais claro o que está acontecendo se você deixar de $0fora:

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

Isso imprime:

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

... porque a atribuição interna ocorre antes da modificação, mas, como observado, a atribuição externa tem precedência - e se expande tanto para a expansão da atribuição interna quanto para a expansão interna modificada.

É claro que nada disso funcionar em todos, se o parâmetro alvo é atribuído - assim você só pode fazê-lo, certamente, se você esvaziar a variável em primeiro lugar ... o que, honestamente, é provavelmente o momento mais conveniente para atribuí-lo depois de tudo .

mikeserv
fonte
+1 para a solução alternativa, embora, como você diz, seja uma solução alternativa provavelmente pior do que atribuir uma variável!
Sparhawk
@ Sparhawk - sim, definitivamente pior. E realmente não há nada errado com isso de qualquer maneira - não há muito a ganhar, exceto a incerteza. Você poderia chegar a algum aliasengano para torná-lo um pouco mais conveniente - mas se vale a pena para você, então você deve configurar uma função para um manuseamento seguro-cotação e fazendo algo w / evalou algo parecido de qualquer maneira. w / eval- se você pode fazer com que os primeiros caracteres da saída do subcomando atinjam a sintaxe de expansão viável - provavelmente será mais fácil. Eu sei que isso seria fácil c / xsel- é preciso stdin - mas xsel?
mikeserv
@Sparhawk - só sei como fazer isso, a propósito, porque em algumas situações pode ser útil - como expansões rápidas ou aqui - nas quais você não pode obter uma atribuição de shell atual para aplicar de outra forma.
mikeserv
1

Se você não deseja criar uma variável, existem outras maneiras de executar a substituição de string:

$ echo $(xclip -o -selection clipboard | sed 's/copi/knott/')
Here's a string I just knotted.
John1024
fonte
Obrigado, eu sabia que poderia usá- sedlo, mas era para ser uma pergunta mais geral sobre aninhamento de substituições.
Sparhawk
@ Sparhawk Que eu saiba, não se pode fazer substituição de variáveis ​​sem ter uma variável.
John1024
Ok, provavelmente essa é a resposta então. Deixarei a pergunta em aberto por alguns dias para ver se mais alguém tem uma resposta referenciada e, em seguida, aceite esta. Obrigado.
Sparhawk
@ Sparhawk Muito bom.
John1024
+1, mas vou aceitar outra resposta , pois fornece uma evidência circunstancial um pouco mais concreta de que não funciona no bash.
Sparhawk