Czy podstawianie poleceń może być zagnieżdżone w podstawianiu zmiennych?


10

Chciałbym użyć podstawienia zmiennej na określonym ciągu, do którego uzyskuję dostęp za pomocą polecenia. Na przykład, jeśli skopiuję coś do schowka, mogę uzyskać do tego dostęp w ten sposób.

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

Jeśli przypiszę ją do zmiennej, będę mógł na niej podstawiać zmienne.

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

Czy jednak istnieje sposób na podstawienie zmiennej bez przypisywania jej do zmiennej? Koncepcyjnie coś takiego.

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

Ta składnia kończy się niepowodzeniem, ponieważ varpowinna to być nazwa zmiennej, a nie ciąg znaków.

Odpowiedzi:


6

Nie możesz. bashi większość innych powłok (oprócz zsh) nie zezwala na zagnieżdżone podstawianie.

Za pomocą zshmożesz wykonać zagnieżdżone podstawienie :

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

Przyjmę tę odpowiedź, ponieważ zawiera ona pewne poszlaki, że nie jest to możliwe bash. (I popycha mnie ponownie w stronę migracji do zsh.)
— Sparhawk

2

Tak, możesz to zrobić - w pewnym sensie. To naprawdę nie jest ładne. Jest bardziej podobny do wbudowanego niż zagnieżdżonego. Problem polega na tym, że musisz operować wartością parametru, który rozwijasz - jeśli ten parametr nie ma wartości, nie zrobisz wiele. Możesz więc przypisać wartość podczas jej rozwijania i nie jest to skrót.

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

Używam $0rozszerzenia param w łańcuchu, aby ukryć przypisanie. Przypisuje wartość var ​​w zagnieżdżonym rozszerzeniu przypisania. Zewnętrzne ma pierwszeństwo - ale ponieważ po prostu rozszerzyłoby się na cokolwiek wewnętrznego, to trudno powiedzieć. Jeśli jednak wyciszymy wewnętrzną ekspansję, a następnie zmodyfikujemy ją, możesz dostać to, czego chcesz. Po skopiowaniu łańcucha do mojego schowka (nie mam xclip- tylko xsel) drukuje:

Here's a string I just knotted.

Jest jednak trochę jaśniejsze, co się dzieje, jeśli $0się pominie:

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

To drukuje:

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

... ponieważ przypisanie wewnętrzne występuje przed modyfikacją, ale, jak wspomniano, przypisanie zewnętrzne ma pierwszeństwo - i rozszerza się zarówno na rozszerzenie przypisania wewnętrznego, jak i na zmodyfikowane rozszerzenie wewnętrzne.

Oczywiście nic z tego nie działa, jeśli parametr docelowy jest już przypisany - więc możesz to zrobić tylko wtedy, gdy opróżnisz zmienną w pierwszej kolejności ... co, szczerze mówiąc, jest to prawdopodobnie najwygodniejszy czas na przypisanie jej w końcu .


+1 za obejście, chociaż, jak mówisz, jest to obejście, które prawdopodobnie jest gorsze niż przypisywanie zmiennej!
— Sparhawk

@Sparhawk - tak, zdecydowanie gorzej. I tak naprawdę nie ma w tym nic złego - nie ma wiele do zyskania poza niepewnością. Możesz wymyślić jakąś aliaspośrednią funkcję, aby uczynić ją trochę wygodniejszą - ale jeśli jest to dla ciebie warte, powinieneś skonfigurować funkcję do obsługi bezpiecznego cytowania i robienia czegoś w / evallub czegoś podobnego. w / eval- jeśli możesz sprawić, że pierwsze znaki wyjściowego polecenia sub będą sprowadzały się do praktycznej składni rozszerzenia - to prawdopodobnie możesz dostać się znacznie dalej. Wiem, że taka rzecz byłaby łatwa w / xsel- wymaga stdin - ale xsel?
— mikeserv

@Sparhawk - tak na marginesie, wiem tylko, jak to zrobić, ponieważ w niektórych sytuacjach może to być przydatne - na przykład szybkie lub dodatkowe rozszerzenia - w których nie można uzyskać bieżącego przypisania powłoki do zastosowania w inny sposób.
— mikeserv

1

Jeśli nie chcesz tworzyć zmiennej, istnieją inne sposoby na zastąpienie łańcucha:

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

Dzięki, wiedziałem, że sedzamiast tego mogę użyć , ale miało to być bardziej ogólne pytanie dotyczące zagnieżdżania podstawień.
— Sparhawk,

@Sparhawk O ile mi wiadomo, nie można podstawiać zmiennych bez posiadania zmiennej.
— John1024,

Okej, to chyba odpowiedź. Pozostawię pytanie otwarte przez kilka dni, aby sprawdzić, czy ktoś ma odpowiedź, na którą się powołuję, a następnie zaakceptuję to inaczej. Dzięki.
— Sparhawk

@Sparhawk Bardzo dobrze.
— John1024,

+1, ale przyjmuję inną odpowiedź , ponieważ zapewnia ona nieco bardziej konkretne poszlaki, że nie działa w trybie bash.
— Sparhawk
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.