Thay thế lệnh có thể được lồng trong thay thế biến?


10

Tôi muốn sử dụng thay thế biến trên một chuỗi cụ thể mà tôi truy cập thông qua một lệnh. Ví dụ, nếu tôi sao chép một cái gì đó vào clipboard của mình, tôi có thể truy cập nó như thế này.

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

Nếu tôi gán nó cho một biến, thì tôi có thể thay thế biến đó trên nó.

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

Tuy nhiên, có cách nào để thay thế biến mà không gán nó cho một biến không? Về mặt khái niệm, một cái gì đó như thế này.

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

Cú pháp này thất bại, vì varphải là một tên biến, không phải là một chuỗi.

Câu trả lời:


6

Không, bạn không thể. bashvà hầu hết các shell khác (trừ zsh) không cho phép thay thế lồng nhau.

Với zsh, bạn có thể thay thế lồng nhau :

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

Tôi sẽ chấp nhận câu trả lời này, vì nó cung cấp một số bằng chứng gián tiếp mà nó không thể thực hiện được bash. (Và đẩy tôi một lần nữa theo hướng di chuyển đến zsh.)
Sparhawk

2

Vâng, bạn có thể làm điều đó - loại. Nó thật sự không đẹp. Nó giống như trong dòng hơn là lồng nhau. Vấn đề là bạn phải vận hành dựa trên giá trị của tham số bạn mở rộng - nếu tham số đó không có giá trị thì bạn sẽ không làm được gì nhiều. Vì vậy, bạn có thể gán giá trị trong khi mở rộng nó và hầu như không phải là phím tắt.

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

Tôi sử dụng $0mở rộng param trong chuỗi để ẩn bài tập. Nó gán giá trị của var trong một mở rộng gán gán lồng nhau. Cái bên ngoài được ưu tiên - nhưng bởi vì nó sẽ mở rộng ra bất cứ thứ gì bên trong không khó để nói. Tuy nhiên, nếu chúng tôi im lặng mở rộng bên trong, sau đó sửa đổi nó, bạn có thể nhận được những gì bạn muốn. Sau khi sao chép chuỗi của bạn vào clipboard của tôi (tôi không có xclip- chỉ xsel) nó sẽ in:

Here's a string I just knotted.

Dù vậy, rõ ràng hơn những gì đang xảy ra nếu bạn rời $0khỏi, mặc dù:

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

Đó là bản in:

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

... bởi vì nhiệm vụ bên trong xảy ra trước khi sửa đổi, nhưng, như đã nói, sự phân công bên ngoài được ưu tiên - và nó mở rộng để mở rộng cả nội phân công của đến nội mở rộng sửa đổi.

Tất nhiên không có cái nào hoạt động cả nếu tham số được nhắm mục tiêu đã được gán - vì vậy bạn chỉ có thể làm điều đó chắc chắn nếu bạn làm trống biến ở vị trí đầu tiên ... mà, thật lòng, có lẽ là thời gian thuận tiện nhất để gán nó .


+1 cho cách giải quyết, mặc dù như bạn nói, đó là cách giải quyết có thể tồi tệ hơn việc gán một biến!
Sparhawk

@Sparhawk - yeah, chắc chắn tệ hơn. Và thực sự không có gì sai cả - dù sao đi nữa - không có gì nhiều để đạt được ngoại trừ sự không chắc chắn. Bạn có thể đưa ra một số aliasquyết định để làm cho nó thuận tiện hơn một chút - nhưng nếu nó có giá trị với bạn thì bạn nên thiết lập một chức năng để xử lý trích dẫn an toàn và làm một evalcái gì đó giống như nó. w / eval- nếu bạn có thể tạo các ký tự đầu tiên của lượng đầu ra của lệnh con thành cú pháp mở rộng khả thi - thì có lẽ bạn có thể dễ dàng hơn rất nhiều. Tôi biết một điều như vậy sẽ dễ dàng với xsel- nó cần stdin - nhưng xsel?
mikeerv

@Sparhawk - Nhân tiện, tôi chỉ biết làm bất kỳ điều nào trong số đó, bởi vì trong một số trường hợp, nó có thể hữu ích - chẳng hạn như mở rộng nhanh chóng hoặc tài liệu ở đây - trong đó bạn không thể áp dụng chuyển nhượng shell hiện tại để áp dụng cách khác.
mikeerv

1

Nếu bạn không muốn tạo biến aa, thì có nhiều cách khác để thực hiện thay thế chuỗi:

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

Cảm ơn, tôi đã biết rằng tôi có thể sử dụng sedthay thế, nhưng nó có nghĩa là nhiều hơn một câu hỏi chung, về việc thay thế lồng nhau.
Sparhawk

@Sparhawk Theo hiểu biết của tôi, người ta không thể thay thế biến mà không có biến.
John1024

Được rồi, đó có lẽ là câu trả lời. Tôi sẽ để câu hỏi mở trong vài ngày để xem có ai khác có câu trả lời được tham khảo không, sau đó chấp nhận câu hỏi này. Cảm ơn.
Sparhawk

@Sparhawk Rất tốt.
John1024

+1, nhưng tôi sẽ chấp nhận một câu trả lời khác , vì nó cung cấp bằng chứng hoàn cảnh cụ thể hơn một chút rằng nó không hoạt động trong bash.
Sparhawk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.