Чи може підстановка команд вкладатись у змінну підстановку?


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має бути ім'ям змінної, а не рядком.

Відповіді:


6

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

З zsh, ви можете зробити вкладені заміни :

$ echo ${$(echo 123)/123/456}   
456

Я прийму цю відповідь, оскільки вона дає певні непрямі докази того, що це неможливо bash. (І знову підштовхує мене до міграції zsh.)
Sparhawk

2

Так, ви можете це зробити. Це насправді не красиво. Він більше схожий на лінію, ніж вкладений. Проблема полягає в тому, що вам доведеться оперувати значенням параметра, який ви розширюєте - якщо цей параметр не має значення, то ви багато чого не зробите. Отже, ви можете призначити значення під час його розширення і навряд чи це ярлик.

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

Я використовую $0розширення парами всередині ланцюга, щоб приховати завдання. Він присвоює значення var в межах вкладеного розширення призначення. Зовнішнє має перевагу, але оскільки воно просто розшириться на все, що робить внутрішній, важко сказати. Однак якщо ми замовчуємо внутрішнє розширення, то модифікуючи його, ви зможете отримати те, що хочете. Після копіювання рядка в мій буфер обміну (у мене немає 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.

... оскільки внутрішнє призначення відбувається перед модифікацією, але, як зазначалося, зовнішнє призначення має перевагу - і воно розширюється як до розширення внутрішнього призначення, так і до модифікованого внутрішнього розширення.

Звичайно, нічого з цього не працює, якщо цільовий параметр вже призначений - тому ви можете це зробити напевно лише, якщо спочатку спустошите змінну ... що, чесно кажучи, мабуть, найзручніший час призначити її все-таки .


+1 для вирішення проблеми, хоча, як ви кажете, це рішення, можливо, гірше, ніж призначення змінної!
Sparhawk

@Sparhawk - так, безумовно, гірше. І з цим насправді немає нічого поганого - нічого не можна отримати, крім невизначеності. Ви можете придумати деяку aliasнепряму сторону, щоб зробити її трохи зручнішою - але, якщо вона того вартує, вам слід налаштувати функцію для безпечного котирування і робити щось з / evalабо щось подібне в будь-якому випадку. w / eval- якщо ви можете зробити перші знаки вихідної суми командного підрозділу синтаксисом розгорнутого розширення - тоді, ймовірно, ви можете набагато простіше отримати набагато далі. Я знаю, що таке може бути легко w / xsel- це потребує stdin - але xsel?
mikeserv

@Sparhawk - Я знаю лише, як зробити що-небудь із цього, до речі, тому що в деяких ситуаціях це може бути корисним - наприклад, підказками або розширеннями тут-doc - в яких ви не можете отримати поточне призначення оболонки, щоб застосувати інакше.
mikeserv

1

Якщо ви не хочете створити змінну aa, то є й інші способи виконання підстановки рядків:

$ echo $(xclip -o -selection clipboard | sed 's/copi/knott/')
Here's a string I just knotted.

Дякую, я знав, що можу використовувати sedнатомість, але це мало бути загальним питанням щодо введення заміни.
Sparhawk

@Sparhawk Наскільки мені відомо, не можна робити заміну змін, не маючи змінної.
John1024,

Гаразд, це, мабуть, відповідь тоді. Залишаю питання відкритим на кілька днів, щоб побачити, чи є ще хто-небудь з посиланням на відповідь, тоді прийміть це в іншому випадку. Дякую.
Sparhawk

@Sparhawk Дуже добре.
John1024

+1, але я прийму іншу відповідь , оскільки це дає дещо конкретніші обґрунтовані докази того, що він не працює в атаці.
Sparhawk
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.