Dapatkah substitusi perintah disarangkan dalam substitusi variabel?

10

Saya ingin menggunakan substitusi variabel pada string tertentu yang saya akses melalui perintah. Misalnya, jika saya menyalin sesuatu ke clipboard saya, saya dapat mengaksesnya seperti ini.

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

Jika saya menugaskannya ke variabel, maka saya bisa melakukan substitusi variabel di dalamnya.

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

Namun, apakah ada cara untuk melakukan substitusi variabel tanpa menugaskannya ke variabel? Secara konseptual, sesuatu seperti ini.

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

Sintaks ini gagal, karena varharus berupa nama variabel, bukan string.

Sparhawk
sumber

Jawaban:

6

Tidak bisa. bashdan sebagian besar kerang lainnya (kecuali zsh) tidak memungkinkan substitusi bersarang.

Dengan zsh, Anda dapat melakukan subtitusi bersarang :

$ echo ${$(echo 123)/123/456}   
456
cuonglm
sumber
Saya akan menerima jawaban ini, karena memberikan beberapa bukti bahwa itu tidak mungkin dilakukan bash. (Dan mendorong saya lagi untuk bermigrasi ke zsh.)
Sparhawk
2

Ya, Anda bisa melakukan itu - semacam itu. Benar-benar tidak cantik. Ini lebih seperti in-line daripada bersarang. Masalahnya adalah Anda harus beroperasi pada nilai parameter yang Anda kembangkan - jika parameter itu tidak memiliki nilai maka Anda tidak akan berbuat banyak. Jadi, Anda dapat menetapkan nilai sambil mengembangkannya dan itu bukan jalan pintas.

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

Saya menggunakan $0ekspansi param dalam rantai untuk menyembunyikan tugas. Ini memberikan nilai var dalam perluasan penugasan bersarang. Bagian luar lebih diutamakan - tetapi karena ia hanya akan meluas ke bagian dalam apa pun yang dilakukan sulit untuk diceritakan. Namun, jika kami membungkam ekspansi batin, maka modifikasi itu Anda bisa mendapatkan apa yang Anda inginkan. Setelah menyalin string Anda ke clipboard saya (saya tidak punya xclip- hanya xsel) itu mencetak:

Here's a string I just knotted.

Namun, sedikit lebih jelas apa yang terjadi jika Anda $0keluar:

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

Itu mencetak:

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

... karena penugasan bagian dalam terjadi sebelum modifikasi, tetapi, seperti yang disebutkan, penugasan bagian luar diutamakan - dan meluas ke ekspansi penugasan bagian dalam maupun ke ekspansi bagian dalam yang dimodifikasi.

Tentu saja tidak ada yang bekerja sama sekali jika parameter yang ditargetkan sudah ditetapkan - jadi Anda hanya bisa melakukannya jika Anda mengosongkan variabel di tempat pertama ... yang, jujur, mungkin waktu yang paling nyaman untuk menetapkannya setelah semua .

mikeserv
sumber
+1 untuk solusinya, meskipun seperti yang Anda katakan, ini solusi yang mungkin lebih buruk daripada menetapkan variabel!
Sparhawk
@Sparhawk - ya, pasti lebih buruk. Dan sebenarnya tidak ada yang salah dengan itu - tidak ada banyak yang bisa didapat kecuali ketidakpastian. Anda bisa membuat beberapa aliastipuan untuk membuatnya sedikit lebih nyaman - tetapi jika nilainya bagi Anda maka Anda harus mengatur fungsi untuk menangani kutipan-aman dan melakukan sesuatu dengan evalatau sesuatu seperti itu pula. w / eval- jika Anda dapat membuat karakter pertama dari jumlah output sub perintah ke sintaks ekspansi yang bisa diterapkan - maka Anda mungkin bisa mendapatkan lebih jauh lebih mudah. Saya tahu hal seperti itu akan mudah w xsel- - dibutuhkan stdin - tetapi xsel?
mikeserv
@Sparhawk - Saya hanya tahu bagaimana melakukan semua itu, ngomong-ngomong, karena dalam beberapa situasi itu bisa berguna - seperti ekspansi cepat atau di sini-doc - di mana Anda tidak bisa mendapatkan tugas shell saat ini untuk menerapkan sebaliknya.
mikeserv
1

Jika Anda tidak ingin membuat variabel aa, maka ada cara lain untuk melakukan penggantian string:

$ echo $(xclip -o -selection clipboard | sed 's/copi/knott/')
Here's a string I just knotted.
John1024
sumber
Terima kasih, saya memang tahu bahwa saya dapat menggunakannya sedsebagai gantinya, tetapi itu dimaksudkan untuk lebih menjadi pertanyaan umum, tentang bersarang substitusi.
Sparhawk
@Sparhawk Setahu saya, orang tidak bisa melakukan penggantian variabel tanpa memiliki variabel.
John1024
Oke, mungkin itu jawabannya. Saya akan membiarkan pertanyaan terbuka selama beberapa hari untuk melihat apakah ada orang lain yang memiliki jawaban yang dirujuk, kemudian menerima yang ini sebaliknya. Terima kasih.
Sparhawk
@Sparhawk Sangat bagus.
John1024
+1, tetapi saya akan menerima jawaban lain , karena memberikan sedikit bukti konkret yang lebih sedikit bahwa itu tidak bekerja dalam bash.
Sparhawk