Khi nào {a, b, c} được mở rộng trong bash, khi nào thì không?


13

Một tập lệnh bash có chứa

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

in

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

khi thực hiện. Đây là những gì tôi mong đợi - khi {a,b}cấu trúc được mở rộng.

Tuy nhiên, khi tập lệnh (khác) chứa

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

nó in

{a,b}-{1,2}

đó không phải là điều tôi mong đợi Tôi dự kiến ​​nó sẽ in a-1 a-2 b-1 b-2. Rõ ràng, {a,b}cấu trúc không được mở rộng.

Tôi có thể làm cho nó mở rộng như vậy

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

Dựa trên những quan sát này, tôi có hai câu hỏi: 1) khi nào {a,b}công trình được mở rộng? 2) là $(echo {a,b}-{1,2})cách ưa thích để kích hoạt mở rộng khi cần thiết?


1
Điều này, ít nhất, phù hợp với thực tế là bạn không thể tạo một biến mảng với một đơn giản =. Ví dụ, v=a-1 a-2sẽ không hoạt động.
grochmal

@grochmal - đó là vì bạn đang gán giá trị vô hướng. v=a-1 a-2có nghĩa là assign 'a-1' to variable v and run 'a-2' v=(a-1 a-2)gán mảng cho biến v. v+=(b-1 b-2)nối vào nó
cas

Câu trả lời:


15

Các nhãn hiệu Bash nói rằng:

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.

Mở rộng cú đúp không có trong danh sách, vì vậy nó không được thực hiện cho nhiệm vụ v={a,b}-{1,2}. Như được đề cập bởi @Wildcard, việc mở rộng đơn giản v=a-1 v=b-1 ...sẽ trở nên vô nghĩa.

Ngoài ra, khi thực hiện echo $v, áp dụng như sau:

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.

Mở rộng niềng răng xảy ra trước khi mở rộng biến đổi, vì vậy niềng răng được chỉ định $vkhông được mở rộng.

Nhưng bạn có thể làm những thứ như thế này:

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

Mở rộng nó $(echo ...)sẽ hoạt động nếu bạn không có bất kỳ khoảng trắng nào trong chuỗi được mở rộng và do đó sẽ không gặp phải vấn đề với việc tách từ. Một cách tốt hơn có thể là sử dụng một biến mảng nếu bạn có thể.

ví dụ: lưu mở rộng vào một mảng và chạy một số lệnh với các giá trị được mở rộng:

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

5

Một điểm thú vị. Có thể hữu ích là đoạn trích sau từ man bash:

Một biến có thể được gán cho bởi một tuyên bố của mẫu

      tên = [ giá trị ]

Nếu giá trị không được đưa ra, biến được gán chuỗi null. Tất cả các giá trị trải qua mở rộng dấu ngã, mở rộng tham số và biến, thay thế lệnh, mở rộng số học và xóa trích dẫn (xem MỞ RỘNG bên dưới).

Lưu ý rằng mở rộng niềng răng KHÔNG được đề cập trong danh sách.

Tuy nhiên, điều này vẫn để lại một câu hỏi, cụ thể là: Làm thế nào shell biết rằng đây là một phép gán biến và do đó không chịu sự mở rộng của niềng răng? Hay chính xác hơn, trình tự phân tích cú pháp được làm rõ và mã hóa ở đâu để trình bao được xác định để xác định các phép gán biến trước khi nó xử lý mở rộng dấu ngoặc? (Đây rõ ràng là cách thức bashhoạt động, nhưng tôi đã không tìm thấy dòng tài liệu chính xác mô tả điều này.)


1
Có lẽ đây ? "2. Các từ không phải là phép gán hoặc chuyển hướng được mở rộng (xem Mở rộng Shell)."
Jeff Schaller

@JeffSchaller, bạn đã đúng. Trên thực tế, câu hỏi này được trả lời tốt nhất bằng cách chỉ đọc phần "MỞ RỘNG QUYỀN ĐƠN GIẢN" ( LESS=+/SIMPLE man bash).
tự đại diện

0

theo kiến ​​thức của tôi, {a, b, c} được mở rộng khi nó trực tiếp lặp lại hoặc được sử dụng với một lệnh, ví dụ: mkdir ~ / {a, b, c}, nhưng khi nó được đặt thành một biến thì nên đánh giá trước lặp lại nó hoặc sử dụng nó như 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

vì bạn có "a" theo sau là "b" theo thứ tự alpha [az] và "1" theo sau là "2" theo thứ tự dec [0-9]: bạn có thể sử dụng dấu chấm kép ".." insteed of comma ", "

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

1
Câu hỏi đặt ra là tại sao vkhông được đặt thành chuỗi ký tự "a-1 a-2 b-1 b-2". Hoặc ít nhất tại sao không có lỗi nào được đưa ra nếu bạn nhập lệnh: v=a-1 v=a-2 v=b-1 v=b-2(mà bạn mong muốn phép gán biến đó sẽ được mở rộng thành). Đó là một câu hỏi hay; Điều này không thực sự trả lời nó.
tự đại diện

@SatoKatsura, "mở rộng ký tự đại diện" nghĩa là gì? Có mở rộng tham số, mở rộng tên đường dẫn và mở rộng cú đúp bất kỳ trong số đó bạn có thể đề cập đến, và tất cả đều khác nhau. Hay bạn có nghĩa là chia từ?
tự đại diện

0

Việc gán cho một biến trong bash không mở rộng biểu thức.

Đối với tập lệnh nhỏ này, x sẽ chứa "*"và không mở rộng "*":

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

Tuy nhiên, một số giá trị được mở rộng, ref. câu trả lời tốt đẹp từ ilkkachu.

Biểu thức được mở rộng khi chúng được đánh giá.

Như thế này:

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

Hoặc như thế này:

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

Hoặc như thế này:

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

Kích hoạt $()là khá phổ biến và tôi nghĩ rằng nó được ưa thích hơn eval, nhưng tốt nhất có lẽ là không kích hoạt đánh giá, cho đến khi biến thực sự được sử dụng trong một lệnh.

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.