วิธีสคริปต์ที่ง่ายที่สุดในการตรวจสอบว่าตัวแปรเปลือกจะถูกส่งออกคืออะไร?


20

สำหรับบางเซสชั่นเชลล์ฉันต้องการพิมพ์แฟล็กคำเตือนหากไม่ได้ตั้งค่าและส่งออกตัวแปรเชลล์

มันค่อนข้างง่ายที่จะทำสิ่งนี้เพื่อพิมพ์ "ข้อผิดพลาด" ในพรอมต์หากSET_MEไม่ได้ตั้งค่าหรือเป็นโมฆะ

test_var () { test -z "$1" && echo Error; }
PS1='$(test_var "$SET_ME") \$ '

อย่างไรก็ตามสิ่งนี้ล้มเหลวในการตั้งค่าสถานะถ้าฉันตั้งค่าSET_MEโดยไม่ส่งออกซึ่งเป็นข้อผิดพลาดที่ฉันต้องการตรวจสอบ มีบางสิ่งที่คล้าย$(bash -c 'test -z "$SET_ME" && echo Error;')หรือส่งออกของ grepping exportมีการตรวจสอบง่าย ๆ ที่ฉันสามารถทำได้เพื่อทดสอบว่าSET_MEมีการส่งออกหรือไม่

โซลูชันที่ไม่ใช่ POSIX และ bash-only เป็นที่ยอมรับ

คำตอบ:


11

ใช้declareคำสั่งและตัวดำเนินการจับคู่นิพจน์ทั่วไป:

test_var () {
    # $1 - name of a shell variable
    var=$1
    [[ -z "${!var}" ]] && echo Error
    [[ $(declare -p $1)  =~ ^declare\ -[aAilrtu]*x[aAilrtu]*\  ]] || echo Error
}

ฉันคิดว่านี่คือสิ่งที่ฉันกำลังมองหา ในทางทฤษฎีแล้วเรื่องอาจจะต้องมีความยืดหยุ่นมากกว่าเช่นถ้าฉันมีตัวแปรส่งออกแบบอ่านอย่างเดียว แต่ในทางปฏิบัติฉันไม่เคยใช้typesetคุณลักษณะอื่น ๆ
CB Bailey

จุดดี. ฉันจะแก้ไขเพื่อลูกหลาน
chepner

ดูเหมือนว่าการพยายามอ้างอิงนิพจน์ทั่วไปหยุดให้มันทำงานเป็นนิพจน์ทั่วไปใน bash> = 3.2
CB Bailey

นอกจากนี้ยังมีความไม่สอดคล้องกัน-z "$1"สมมติว่าฉันผ่านค่าของตัวแปรไปที่test_var(เหมือนฉัน) ในขณะที่declare -pคาดว่าชื่อของมัน test_exported_notnull () { re='^declare -\w*x'; [[ -n $(eval echo \$$1) ]] && [[ $(declare -p "$1") =~ $re ]]; }ฉันมากับการทดสอบนี้ซึ่งใช้ชื่อของตัวแปรเปลือกนี้:
CB Bailey

เพื่อหลีกเลี่ยงการevalเพียงเพิ่มนี้บรรทัดแรก: แล้วใช้var=$1 [[ -z "${!var}" ]] && echo Error
chepner

4

ฉันทราบว่าคำถามมีอายุ 3 ปี แต่อาจพบวิธีแก้ไขปัญหาต่อไปนี้ได้ง่ายขึ้น:

[ "$(bash -c 'echo ${variable}')" ]

คำตอบถ้าตัวแปรถูกส่งออกและมีค่าไม่ว่าง


4

ในBash 4.4 หรือใหม่กว่าคุณสามารถใช้การ${parameter@a} ขยายพารามิเตอร์ของเชลล์เพื่อรับรายการแอททริบิวเกี่ยวกับพารามิเตอร์รวมถึงหากมีการส่งออก

นี่คือฟังก์ชั่นพื้นฐานที่แสดงให้เห็น${parameter@a}ว่าตัวแปรที่กำหนดถูกส่งออกโดยใช้ชื่อหรือไม่:

function is_exported {
    local name="$1"
    if [[ "${!name@a}" == *x* ]]; then
        echo "Yes - '$name' is exported."
    else
        echo "No - '$name' is not exported."
    fi
}

ตัวอย่างการใช้งาน:

$ is_exported PATH
Yes - 'PATH' is exported.
$ foo=1 is_exported foo
Yes - 'abc' is exported.
$ bar=1; is_exported bar
No - 'abc' is not exported.
$ export baz=1; is_exported baz
Yes - 'baz' is exported.
$ export -n baz; is_exported baz
No - 'baz' is not exported.
$ declare -x qux=3; is_exported qux
Yes - 'qux' is exported.

มันทำงานอย่างไร:

รูปแบบที่ส่งคืนโดย${parameter@a}มีหนึ่งอักขระต่อแอตทริบิวต์โดยมีความหมายของอักขระแต่ละตัวที่มาจากตัวเลือกที่สอดคล้องกันจากคำสั่งประกาศ - ในกรณีนี้เราต้องการค้นหาx- ส่งออก


คำตอบที่ดีที่สุดถ้าคุณใช้ Bash 4.4 หรือใหม่กว่า!
แอนดี้

3

คุณสามารถใช้compgenกับ-Xตัวเลือกเพื่อตรวจสอบว่าตัวแปรถูกเอ็กซ์พอร์ตหรือไม่:

compgen -e -X "!$MAY_BE_EXPORTED_VARIABLE"

เช่น:

$ NOT_EXPORTED="xxx"
$ compgen -e -X '!SHELL'
SHELL
$ compgen -e -X '!NOT_EXPORTED'
$ echo $?
1

คำตอบที่เข้ากันได้ดีที่สุด! ช้ากว่าสองเท่าของโซลูชัน $ {parameter @ a} แต่เข้ากันได้ดีกว่าสำหรับกรณี bash 3.2
Andy

2

ถ้าฉันลาออกจากการต้องใช้exportและgrepการทดสอบที่ง่ายที่สุดอาจเป็นอะไรเช่นนี้

export | grep -Eq '^declare -x SET_ME='

หรือถ้าฉันต้องการไม่เป็นโมฆะเช่นกัน:

export | grep -Eq '^declare -x SET_ME=".+"'

1
POSIX 7 บอกว่าexportมันไม่ได้ระบุและกำหนดรูปแบบที่แม่นยำสำหรับexport -pคล้ายกับทุบตีexportแต่แตกต่างกัน แต่ทุบตีดูเหมือนจะไม่สนใจ POSIX และใช้รูปแบบเดียวexportกับexport -p!
Ciro Santilli 新疆改造中心法轮功六四事件

1

exportคำสั่งที่กำหนดโดยไม่มีพารามิเตอร์ให้รายชื่อที่ส่งออกในสภาพแวดล้อมปัจจุบันนี้:

$ FOO1=test
$ FOO2=test
$ export | grep FOO
$ export FOO2
$ export | grep FOO
declare -x FOO2="test"

การตัดและการล่อลวงบางอย่างทำให้ขนขุย:

export | cut -d' ' -f 3- | sed s/=.*//

มีรายการส่งออกของคุณพร้อมสำหรับการดำเนินการเพิ่มเติม


1
มันใช้งานได้ แต่ฉันหวังว่าจะได้คำตอบที่เบากว่าโดยมีส้อมน้อยกว่า (เพราะฉะนั้น "สั้น [... ] การเอาท์พุทของ grepping export") เนื่องจากการใช้งานตามแผนของฉันอยู่ในทันที
CB Bailey

@ CharlesBailey: ฉันเข้าใจ ฉันมาที่นี่โดยค้นหา bash manpage เพื่อหาexportและนี่คือสิ่งเดียวที่ฉันคิดขึ้นมา ไม่มีความช่วยเหลือจากเปลือกใดหนี exportเป็น builtin อยู่แล้ว grepแต่ผมสงสัยคุณสามารถหลีกเลี่ยง
DevSolar

1

วิธีที่ง่ายที่สุดที่ฉันคิดในปัจจุบัน:

[ bash -c ': ${v1?}' 2>/dev/null ]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.