วิธีทำให้ตัวแปรจากเชลล์ย่อยพร้อมใช้งานในพาเรนต์เชลล์


11

ฉันได้เขียนสคริปต์ที่รวดเร็วและสกปรกเพื่อรายงานเวลาจากบริการเว็บ:

BASE_URL='http://example.com/json/webservice/'
FIRST=1
FINAL=10000

for report_code in $(seq 1 $FINAL); do
  (time -p response=$(curl --write-out %{http_code} --silent -O ${BASE_URL}/${report_code}) ) 2> ${report_code}.time

  echo $response  # <------- this is out of scope!  How do I fix that?
  if [[ $response = '404' ]]; then
    echo "Deleting report # ${report_code}!"
    rm ${report_code}
  else
    echo "${report_code} seems to be good!"
  fi
done

ฉันต้องการตัดtimeคำสั่งใน$responseเชลล์ย่อยเพื่อให้ฉันสามารถเปลี่ยนทิศทางเอาต์พุต แต่นั่นทำให้ค่าไม่พร้อมใช้งานกับพาเรนต์เชลล์ ฉันจะแก้ไขปัญหานี้ได้อย่างไร

คำตอบ:


11

คุณไม่สามารถนำค่าของตัวแปรจาก subshell ไปที่ parent ของมันได้โดยไม่ต้องทำการสื่อสารที่ผิดพลาดและการสื่อสารที่ยุ่งยาก

โชคดีที่คุณไม่ต้องการ subshell ที่นี่ การเปลี่ยนเส้นทางต้องการเพียงการจัดกลุ่มคำสั่งด้วย{ … }ไม่ใช่ subshell

{ time -p response=$(curl --write-out '%{http_code}' --silent -O "${BASE_URL}/${report_code}"); } 2> "${report_code}.time"

(อย่าลืมเครื่องหมายคำพูดคู่รอบ ๆ การแทนที่ตัวแปร )


มันตลกที่ทุกภาษาการเขียนโปรแกรมสามารถทำได้ ฉันใช้ googling ไปแล้ว 1 ชั่วโมงโดยที่ไม่มีวิธีแก้ไขที่เป็นไปได้ ฉันผิดหวัง
ถึงกระของ

1
@ ToKra ไม่ภาษาการเขียนโปรแกรมสามารถทำได้ (เกือบ) การเขียนโปรแกรมภาษาใด ๆ ที่สามารถนำค่าตัวแปรจากsubroutine หรือคำสั่งบล็อกไปยังผู้ปกครองของตนและว่าสิ่งที่ฉันอธิบายในคำตอบของฉัน: ใช้คำสั่งการจัดกลุ่ม{ … }แทน ( … )subshell
Gilles 'หยุดความชั่วร้าย' ใน

4

เพื่อนผู้ใช้ U&L: ก่อนที่จะลดคำตอบสำหรับการใช้งาน C-style พร้อมmain()ฟังก์ชั่นกรุณาเยี่ยมชมลิงค์นี้: https://unix.stackexchange.com/a/313561/85039การใช้ฟังก์ชั่นหลักในสคริปต์เป็นวิธีปฏิบัติทั่วไปที่ผู้เชี่ยวชาญหลายคนใช้ ในสนาม


ตามที่ Gilles ชี้ให้เห็น subshells ไม่สามารถทำให้ตัวแปรมีอยู่นอกสภาพแวดล้อม แต่ลองเข้าใกล้ปัญหานี้จากมุมมองอื่น - ถ้าคุณเขียนสคริปต์ของคุณในฟังก์ชั่นเป็นไปได้ที่จะประกาศตัวแปรเป็นlocalและสามารถแก้ไขได้

จากคู่มือของ bash 4.3 localคำอธิบาย:

... เมื่อใช้งานโลคอลภายในฟังก์ชั่นจะทำให้ชื่อตัวแปรมีขอบเขตที่มองเห็นได้ซึ่ง จำกัด อยู่ที่ฟังก์ชั่นนั้นและลูก ๆ ...

ตัวอย่าง:

#!/bin/bash

outter()
{
    for i in $(seq 1 3)
    do
        var=$i
    done
}

main()
{
    local var=0
    outter
    echo $var
}
main "$@"
$ ./testscript.sh                                                                                                        
3

อย่างที่คุณเห็นหลังจากการวนซ้ำ 3 ครั้งของฟังก์ชันการวนซ้ำตัวแปรจะถูกปรับเปลี่ยน


อืมมพฤติกรรมที่ไม่ได้ใช้งานง่ายสำหรับโปรแกรมเมอร์ C ปกติผมคาดหวังที่จะอ้างถึงอินสแตนซ์ระดับโลกของoutter var
Ruslan

คำตอบนี้มีข้อบกพร่อง ไม่จำเป็นต้องใช้ในการโทรออก"$var" outterมันไม่ได้ทำอะไรเลย และlocal var=0ไม่ทำอะไรเลย ouf การโทรoutterจะเขียนทับvarตามที่คุณระบุ
Golar Ramblar

@GolarRamblar ฉันได้ลบออก"$var"เป็นอาร์กิวเมนต์ตำแหน่งถึงoutter; เพื่อความเป็นธรรมนี่เป็นนิสัย คุณสามารถอธิบายอย่างละเอียดได้local var=0 หรือไม่?
Sergiy Kolodyazhnyy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.