ข้อผิดพลาดที่เป็นไปได้ใน Bash?: foo () {echo“ $ {var [0]}”; }; var = (bar baz) foo


22

ระบบปฏิบัติการ : Ubuntu 16.04.3

เชลล์ : ทุบตี 4.3.48


ฉันรู้ว่าเป็นไปได้ที่จะเปลี่ยนแปลงเนื้อหาของตัวแปรชั่วคราวในvar=value commandซึ่งอาจIFS= read -r varเป็นกรณีที่น่าสังเกตมากที่สุดของเรื่องนี้

และด้วยวิกิของเกร็กฉันก็เข้าใจเช่นกัน:

# Why this
foo() { echo "$var"; }
var=value foo

# And this does work
var=value; echo "$var"

# But this doesn't
var=value echo "$var"

สิ่งนี้ทำให้ฉันเข้าใจได้:

$ foo() { echo "${var[0]}"; }
$ var=(bar baz) foo
(bar baz)

เท่าที่ผมรู้ (และต่อไปนี้ตรรกะของตัวอย่างก่อนหน้านี้) ก็ควรพิมพ์ไม่bar(bar baz)

สิ่งนี้เกิดขึ้นกับฉันหรือเปล่า นี่เป็นพฤติกรรมที่ตั้งใจและฉันขาดอะไรไปหรือเปล่า? หรือนี่เป็นข้อบกพร่องหรือไม่?


3
บางทีมันอาจจะเกี่ยวข้องกับข้อเท็จจริงที่ว่าทุบตีไม่สนับสนุนอาร์เรย์เป็นตัวแปรด้านสิ่งแวดล้อม?
Jesse_b

3
@Jesse_b บางที แต่เมื่อฉันใช้export var=(foo bar); echo "${var[0]}"มันพิมพ์ไม่ได้foo (foo bar)
nxnev

1
แปลกที่ทำงานสำหรับฉันเช่นกัน และการใช้exportมันแสดง:declare -ax var=([0]="foo" [1]="bar")
Jesse_b

3
สภาพแวดล้อมต้องไม่มีอาร์เรย์ AFAIK เช่นexport i_am_array=(foo bar); /usr/bin/env | grep i_am_arrayไม่มีผลลัพธ์ที่นี่
derobert

3
นอกจากนี้: foo() { declare -p var; } ; var=(bar baz) fooให้การdeclare -x var="(bar baz)"ยืนยันว่ามันถูกใช้เป็นสตริงไม่ใช่อาร์เรย์
Derobert

คำตอบ:


19

โดยทั่วไปเรียก:

var=value cmd

โดยที่cmdฟังก์ชั่นไม่สามารถพกพาได้

ด้วยbashที่ใช้งานได้เฉพาะกับตัวแปรสเกลาร์ (และx=(...)แยกวิเคราะห์เป็นอาร์เรย์ แต่กำหนดเป็นสเกลาร์) และมีปัญหาจำนวนมากที่มีการกำหนดขอบเขตถ้าคุณทำเช่นนั้นด้วยksh93และyashจะทำงานได้ แต่นิยามตัวแปรยังคงอยู่หลังจากนั้น ด้วยmkshคุณจะได้รับข้อผิดพลาดทางไวยากรณ์ ในเชลล์เป้าหมายมันไม่ทำงานเลยแม้แต่กับตัวแปรสเกลาร์

โปรดทราบด้วยว่าถึงแม้จะมีตัวแปรสเกลาร์ไม่ว่าตัวแปรนั้นจะถูกส่งออกภายในฟังก์ชั่น (นั่นคือส่งผ่านไปยังคำสั่งที่กำลังดำเนินการ) จะแตกต่างกันไปจากเชลล์หนึ่งไปยังเชลล์ (ใน bash, yash, mksh, zsh เถ้า).

ใช้งานได้ตามที่คุณคาดหวังzshเท่านั้น โปรดสังเกตว่าzshดัชนีอาร์เรย์เริ่มต้นที่ 1

bash-4.4$ zsh
$ a=(before value)
$ f() echo $a[1]
$ a=(temp value) f
temp
$ echo $a[1]
before

12

มันไม่ใช่แค่บั๊กมันดูเหมือนว่าจะเป็นฟีเจอร์ที่ไม่ได้ใช้งานเลยโดยที่ไม่มีแผนเลย โพสต์รายการจดหมายนี้จากปี 2014 มีสิ่งนี้จากผู้สร้าง:

โชคดีที่ใน bash 4.3 (patchlevel 25) คุณไม่สามารถเพียงแค่ -DARRAY_EXPORT และรับการนำเข้า / ส่งออกตัวแปรอาเรย์ รหัสไม่ได้รวบรวมและถ้าคุณแก้ไขมันจะไม่เชื่อมโยงและถ้าคุณแก้ไขได้ดีคุณจะจบลงด้วยปัญหาต่อไปนี้

นั่นเป็นปัญหาที่ต้องทำเพื่อสิ่งนี้ ฉันไม่มีแผนเปิดใช้งานการส่งออกอาร์เรย์

ดึงจาก repo คอมไพล์ล่าสุดสำหรับ Bash ได้ในvariables.c:

  #  if ARRAY_EXPORT
        /* Array variables may not yet be exported. */

แนะนำว่าสิ่งที่มีไม่สมบูรณ์


5
ที่นี่มีไว้สำหรับฟังก์ชั่นดังนั้นจึงไม่มีคำถามว่าจะส่งออกสิ่งใดเนื่องจากไม่มีการexecve()เรียกระบบ ดูzshเชลล์ที่รองรับฟังก์ชั่นการโทรด้วยอาเรย์ที่ตั้งค่าไว้ชั่วคราว
Stéphane Chazelas

@ StéphaneChazelas แต่การเปลี่ยนแปลงสภาพแวดล้อม (โดยการเพิ่มตัวแปรใหม่) และจากนั้นย้อนกลับไปกลับมาหลังจากที่ทำงานเสร็จสมบูรณ์ (I am เกี่ยวกับกรณีนี้my_var=one func_bar) เราสามารถพูดได้ไหมว่าexportมันเป็นการเพิ่มสิ่งแวดล้อมและด้วยเหตุนี้การส่งออกจึงถูกใช้ที่นี่ภายใต้ประทุน? ดูคำตอบของฉันฉันเพิ่มรหัสการสาธิต
MiniMax

10

จากส่วนman bashของ BUGS (เวอร์ชันbash4.3 คือ):

ข้อบกพร่อง

   Array variables may not (yet) be exported.

รหัสถัดไปแสดงให้เห็นว่ามีตัวแปรชั่วคราวในสภาพแวดล้อมเฉพาะขณะที่ฟังก์ชันกำลังทำงาน เมื่อฟังก์ชั่นเสร็จสมบูรณ์ตัวแปรชั่วคราวจะหายไป

### defining the "bar" function
### it pass all environment variables to the "grep" command
### and the "grep" prints the only "my_var" variable from it
bar() { env | grep my_var=; }

### calls the "bar" function with the temporary 
### variable "my_var" created and assigned.
my_var=one bar

my_var=one         ### The output. The environment contains the "my_var" variable

### checks, does the environment still have the "my_var" variable
### (It doesn't have.)
env | grep my_var=
                   ### The output is empty,
                   ### the environment doesn't contain the "my_var" variable

ข้อมูลที่เกี่ยวข้อง:

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.