Kapan {a, b, c} diperluas dalam bash, kapan bukan?

13

Skrip bash yang berisi

for i in {a,b}-{1,2}; do
  echo $i;
done

cetakan

a-1
a-2
b-1
b-2

ketika dieksekusi. Inilah yang saya harapkan - saat {a,b}konstruksinya diperluas.

Namun, ketika skrip (lain) berisi

v={a,b}-{1,2}
echo $v

itu mencetak

{a,b}-{1,2}

yang bukan itu yang saya harapkan. Saya berharap untuk mencetak a-1 a-2 b-1 b-2. Jelas, {a,b}konstruksinya tidak diperluas.

Saya bisa membuatnya berkembang seperti itu

v=$(echo {a,b}-{1,2})

Berdasarkan pengamatan ini saya punya dua pertanyaan: 1) kapan {a,b}konstruk diperluas? 2) apakah $(echo {a,b}-{1,2})cara yang disukai untuk memicu ekspansi bila diperlukan?

René Nyffenegger
sumber
1
Ini, setidaknya, konsisten dengan fakta bahwa Anda tidak dapat membuat variabel array dengan sederhana =. Misalnya, v=a-1 a-2tidak akan berfungsi.
grochmal
@ grochmal - itu karena Anda menetapkan nilai skalar. v=a-1 a-2berarti assign 'a-1' to variable v and run 'a-2' v=(a-1 a-2)menetapkan array ke variabel v. v+=(b-1 b-2)menambahkannya.
cas

Jawaban:

15

The pengguna Bash mengatakan bahwa:

SIMPLE COMMAND EXPANSION
When a simple command is executed, the shell performs the following
expansions, assignments, and redirections, from left to right.
[...]
4. The  text  after the = in each variable assignment undergoes tilde
   expansion, parameter expansion, command substitution, arithmetic
   expansion, and quote removal before being assigned to the variable.

Perluasan brace tidak ada dalam daftar, sehingga tidak dilakukan untuk penugasan v={a,b}-{1,2}. Seperti yang disebutkan oleh @Wildcard, ekspansi sederhana v=a-1 v=b-1 ...menjadi tidak masuk akal.

Juga, ketika menjalankan echo $v, hal berikut ini berlaku:

EXPANSION
Expansion is performed on the command line after it has been split
into words. [...]

The order of expansions is: brace expansion; tilde expansion, 
parameter and variable expansion, arithmetic expansion, and command
substitution (done in a left-to-right fashion); word splitting; and
pathname expansion.

Ekspansi brace terjadi sebelum ekspansi variabel, sehingga kawat gigi yang ditugaskan $vtidak diperluas.

Tetapi Anda dapat melakukan hal-hal seperti ini:

$ var_this=foo var_that=bar
$ echo $var_{this,that}
foo bar

Perluasan dengan itu $(echo ...)akan berfungsi jika Anda tidak memiliki spasi kosong di string yang akan diperluas, dan karenanya tidak akan mengalami masalah dengan pemisahan kata. Cara yang lebih baik adalah menggunakan variabel array jika Anda bisa.

mis. simpan ekspansi ke dalam array dan jalankan beberapa perintah dengan nilai yang diperluas:

$ v=( {a,b}-{1,2} )
$ some_command "${v[@]}"
ilkkachu
sumber
5

Poin yang menarik. Mungkin membantu adalah kutipan berikut dari man bash:

Sebuah variabel dapat diberikan oleh pernyataan dari bentuk

      name = [ value ]

Jika nilai tidak diberikan, variabel tersebut diberikan string nol. Semua nilai mengalami ekspansi tilde, ekspansi parameter dan variabel, substitusi perintah, ekspansi aritmatika, dan penghapusan kutipan (lihat EKSPANSI di bawah).

Perhatikan bahwa ekspansi brace TIDAK disebutkan dalam daftar.

Namun ini masih menimbulkan pertanyaan, yaitu: Bagaimana shell tahu bahwa ini adalah penugasan variabel dan dengan demikian tidak dikenakan ekspansi brace? Atau lebih tepatnya, di mana urutan parsing diklarifikasi dan dikodifikasikan sedemikian sehingga shell didefinisikan untuk mengidentifikasi tugas variabel sebelum menangani ekspansi brace? (Ini jelas cara bashkerjanya, tetapi saya belum menemukan baris dokumentasi yang menjelaskan hal ini.)

Wildcard
sumber
1
Mungkin ini ? "2. Kata-kata yang bukan penugasan atau pengalihan variabel diperluas (lihat Ekspansi Shell)."
Jeff Schaller
@ JeffSchaller, Anda benar. Sebenarnya pertanyaan ini paling baik dijawab dengan hanya membaca bagian "SIMPLE COMMAND EXPANSION" ( LESS=+/SIMPLE man bash).
Wildcard
0

menurut pengetahuan lil saya {a, b, c} diperluas ketika langsung digemakan atau digunakan dengan perintah misalnya: mkdir ~ / {a, b, c}, tetapi ketika itu diatur ke variabel itu harus dievaluasi sebelum gema atau gunakan sebagai arggument!

u@h:~$ echo {a,b}-{1,2}
a-1 a-2 b-1 b-2
u@h:~$ v={a,b}-{1,2}
u@h:~$ echo $v
{a,b}-{1,2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

karena Anda memiliki "a" diikuti oleh "b" dalam urutan alpha [az], dan "1" diikuti oleh "2" dalam urutan Desember [0-9]: Anda dapat menggunakan periode ganda ".." insteed of koma ", "

u@h:~$ echo {a..b}-{1..2}
a-1 a-2 b-1 b-2
u@h:~$ v={a..b}-{1..2}
u@h:~$ echo $v
{a..b}-{1..2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2
Jonah
sumber
1
Pertanyaannya adalah mengapa vtidak diatur ke string literal "a-1 a-2 b-1 b-2". Atau setidaknya mengapa tidak ada kesalahan yang dilemparkan saat Anda mendapatkan jika Anda mengetik perintah: v=a-1 v=a-2 v=b-1 v=b-2(yang Anda harapkan penugasan variabel diperluas ke). Itu pertanyaan yang bagus; ini tidak benar-benar menjawabnya.
Wildcard
@SatoKatsura, apa yang dimaksud dengan "ekspansi wildcard"? Ada ekspansi parameter, ekspansi pathname, dan ekspansi brace — yang mana Anda bisa merujuk, dan semuanya berbeda. Atau maksud Anda pemisahan kata?
Wildcard
0

Menetapkan ke variabel dalam bash tidak memperluas ekspresi.

Untuk skrip kecil ini, x akan berisi "*"dan bukan perluasan dari "*":

#!/bin/bash
x=*
echo "$x"

Namun, beberapa nilai diperluas, ref. jawaban yang bagus dari ilkkachu.

Ekspresi diperluas ketika mereka dievaluasi.

Seperti ini:

x=$(echo *)        # <-- evaluation of "*"
echo "$x"

Atau seperti ini:

x=*
echo $x            # <-- evaluation of $x

Atau seperti ini:

x=*
eval echo "$x"     # <-- evaluation of `echo *`

Memicu $()cukup umum dan saya pikir itu lebih disukai eval, tetapi yang terbaik mungkin tidak memicu evaluasi sama sekali, sampai variabel benar-benar digunakan dalam suatu perintah.

Alexander
sumber