Может ли подстановка команд быть вложенной в подстановку переменных?

10

Я хотел бы использовать подстановку переменных в конкретной строке, к которой я обращаюсь через команду. Например, если я скопирую что-то в буфер обмена, я получу к нему доступ следующим образом.

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

Если я назначу его переменной, то я могу сделать замену переменной на нем.

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

Тем не менее, есть ли способ сделать подстановку переменной, не назначая ее переменной? Концептуально как то так.

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

Этот синтаксис не работает, потому что varдолжно быть имя переменной, а не строка.

Sparhawk
источник

Ответы:

6

Нет, ты не можешь. bashи большинство других оболочек (кроме zsh) не допускают вложенную замену.

С помощью zshвы можете сделать вложенную замену :

$ echo ${$(echo 123)/123/456}   
456
cuonglm
источник
Я приму этот ответ, поскольку он предоставляет некоторые косвенные доказательства того, что это невозможно в bash. (И снова подталкивает меня к миграции zsh.)
Sparhawk
2

Да, вы можете сделать это - вроде. Это действительно не красиво. Это больше похоже на встроенный, чем вложенный. Проблема в том, что вы должны работать со значением раскрываемого параметра - если этот параметр не имеет значения, вы не будете делать много. Таким образом, вы можете присвоить значение при его расширении, и вряд ли это будет ярлык.

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

Я использую $0расширение параметра в цепочке, чтобы скрыть назначение. Он присваивает значение переменной в раскрытии вложенного присваивания. Внешнее имеет приоритет - но потому что оно просто расширится до того, что делает внутренний, трудно сказать. Однако, если мы заглушим внутреннее расширение, то изменив его, вы сможете получить то, что хотите. После копирования вашей строки в мой буфер обмена (у меня нет xclip- просто xsel), он печатает:

Here's a string I just knotted.

Немного яснее, что происходит, если вы $0пропустите:

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

Это печатает:

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

... потому что внутреннее назначение происходит до модификации, но, как уже было отмечено, внешнее назначение имеет приоритет - и оно распространяется как на расширение внутреннего назначения, так и на модифицированное внутреннее расширение.

Конечно, ничего из этого не работает вообще, если целевой параметр уже назначен - так что вы можете сделать это только уверенно, если сначала очистите переменную ... что, честно говоря, вероятно, самое подходящее время для его назначения после всех ,

mikeserv
источник
+1 за обходной путь, хотя, как вы говорите, это обходной путь, который, вероятно, хуже, чем присвоение переменной!
Sparhawk
@ Sparhawk - да, определенно хуже. И действительно, в этом нет ничего плохого - в этом нет ничего, кроме неопределенности. Вы можете придумать какое-то aliasкосвенное указание, чтобы сделать его немного более удобным - но если оно того стоит, вам следует настроить функцию для обработки безопасных цитат и делать что-то с / evalили что-то подобное в любом случае. w / eval- если вы можете сделать первые символы выходной команды command sub равными работающему синтаксису расширения - тогда вы, вероятно, сможете продвинуться намного проще. Я знаю, что такое было бы легко с / xsel- это требует стандартного ввода - но xsel?
mikeserv
@Sparhawk - кстати, я знаю только то, как это можно сделать, потому что в некоторых ситуациях это может быть полезно - например, при расширении с использованием приглашения или здесь-документа - в котором вы не можете применить текущее назначение оболочки для применения в противном случае.
mikeserv
1

Если вы не хотите создавать переменную, то есть другие способы выполнения подстановки строк:

$ echo $(xclip -o -selection clipboard | sed 's/copi/knott/')
Here's a string I just knotted.
John1024
источник
Спасибо, я знал, что мог бы использовать sedвместо этого, но это был более общий вопрос о вложенности подстановок.
Sparhawk
@Sparhawk Насколько мне известно, никто не может сделать подстановку переменных без наличия переменной.
John1024
Хорошо, это, вероятно, ответ. Я оставлю вопрос открытым на несколько дней, чтобы посмотреть, есть ли у кого-либо другой ответ, на который есть ссылка, а затем приму этот вопрос в противном случае. Спасибо.
Sparhawk
@ Sparhawk Очень хорошо.
John1024
+1, но я собираюсь принять другой ответ , поскольку он предоставляет несколько более конкретные косвенные доказательства того, что он не работает в bash.
Sparhawk