ฉันพบสคริปต์ที่มีฟังก์ชันที่ตรวจสอบว่ามีการตั้งค่าตัวแปร แต่ฉันไม่เข้าใจมันเป็นอย่างดี
check_if_variable_is_set() {
var_name=$1
if [ -z "${!var_name+x}" ]; then
false
else
true
fi
}
เกิดอะไรขึ้นกับการทดแทนนี้
ฉันพบสคริปต์ที่มีฟังก์ชันที่ตรวจสอบว่ามีการตั้งค่าตัวแปร แต่ฉันไม่เข้าใจมันเป็นอย่างดี
check_if_variable_is_set() {
var_name=$1
if [ -z "${!var_name+x}" ]; then
false
else
true
fi
}
เกิดอะไรขึ้นกับการทดแทนนี้
คำตอบ:
ใน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:]]
จะตรวจสอบอักขระตามตัวอักษรในโลแคลของคุณในขณะที่เชลล์บางตัวยอมรับเฉพาะอักขระตัวอักษรจากชุดอักขระแบบพกพาในตัวแปร)