การแทนที่ $ {! var_name + x} หมายถึงอะไร


10

ฉันพบสคริปต์ที่มีฟังก์ชันที่ตรวจสอบว่ามีการตั้งค่าตัวแปร แต่ฉันไม่เข้าใจมันเป็นอย่างดี

check_if_variable_is_set() {
    var_name=$1
    if [ -z "${!var_name+x}" ]; then
        false
    else
        true
    fi
}

เกิดอะไรขึ้นกับการทดแทนนี้


ที่เกี่ยวข้อง$ {!} FOO และ zsh
αғsнιη

คำตอบ:


17

ในbashเปลือก${!var}เป็นตัวแปรทางอ้อม $varมันขยายไปยังค่าของตัวแปรที่มีชื่อจะถูกเก็บไว้ใน

การขยายตัวแปร${var+value}คือการขยาย POSIXที่ขยายไปvalueหากvarตั้งค่าตัวแปร(ไม่ว่าค่านั้นจะว่างเปล่าหรือไม่ก็ตาม)

รวมเหล่านี้${!var+x}จะขยายไปxหากตัวแปรที่มีชื่อถูกเก็บไว้ในการ$varตั้งค่า

ตัวอย่าง:

$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"

(บรรทัดว่างเป็นเอาต์พุต)


ฟังก์ชันในคำถามสามารถย่อให้สั้นลงได้

check_if_variable_is_set () { [ -n "${!1+x}" ]; }

หรือแม้กระทั่ง:

check_if_variable_is_set () { [ -v "$1" ]; }

หรือแม้กระทั่ง:

check_if_variable_is_set()[[ -v $1 ]]

โดยที่-vการbashทดสอบเกี่ยวกับชื่อตัวแปรซึ่งจะเป็นจริงถ้าตัวแปรที่ตั้งชื่อถูกตั้งค่าและเท็จเป็นอย่างอื่น


POSIXly สามารถเขียนได้:

check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }

โปรดทราบว่าสิ่งเหล่านี้เป็นช่องโหว่ในการฉีดคำสั่งที่อาจเกิดขึ้นหากอาร์กิวเมนต์ของฟังก์ชั่นนั้นสิ้นสุดลงด้วยการควบคุมของผู้โจมตี check_if_variable_is_set 'a[$(id>&2)]'ลองยกตัวอย่างเช่นกับ

เพื่อป้องกันสิ่งนั้นคุณอาจต้องการตรวจสอบว่าอาร์กิวเมนต์เป็นชื่อตัวแปรที่ถูกต้องก่อน สำหรับตัวแปร:

check_if_variable_is_set() {
  case $1 in
    ("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
    (*)  eval '[ -n "${'"$1"'+x}" ]'
  esac
}

(โปรดทราบว่า[[:alpha:]]จะตรวจสอบอักขระตามตัวอักษรในโลแคลของคุณในขณะที่เชลล์บางตัวยอมรับเฉพาะอักขระตัวอักษรจากชุดอักขระแบบพกพาในตัวแปร)


ไม่มีสิ่งใดในโลกที่สมบูรณ์แบบไปกว่านี้ คุณสมควรได้รับคุกกี้สำหรับสิ่งนั้น
Karim Manaouil

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