Apa arti dari substitusi $ {! Var_name + x}?

10

Saya menemukan skrip yang memiliki fungsi yang memeriksa apakah suatu variabel diset tetapi saya tidak memahaminya dengan baik.

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

Apa yang sebenarnya terjadi dengan penggantian ini?

Karim Manaouil
sumber
terkait $ {! FOO} dan zsh .
αғsнιη

Jawaban:

17

Dalam bashshell, ${!var}adalah tipuan variabel. Itu memperluas ke nilai variabel yang namanya disimpan $var.

Ekspansi variabel ${var+value}adalah ekspansi POSIX yang berkembang ke valuejika variabel vardiatur (tidak peduli apakah nilainya kosong atau tidak).

Menggabungkan ini, ${!var+x}akan diperluas ke xjika variabel yang namanya disimpan $vardiatur.

Contoh:

$ 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}}"

(baris kosong sebagai output)


Fungsi dalam pertanyaan dapat disingkat menjadi

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

atau bahkan:

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

atau bahkan:

check_if_variable_is_set()[[ -v $1 ]]

Di mana -vadalah bashtes pada nama variabel yang akan menjadi kenyataan jika variabel bernama diatur, dan false jika tidak.


POSIXly, itu bisa ditulis:

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

Perhatikan bahwa semua itu adalah potensi kerentanan injeksi perintah jika argumen pada fungsi itu bisa berakhir di bawah kendali seorang penyerang. Coba misalnya dengan check_if_variable_is_set 'a[$(id>&2)]'.

Untuk mencegah hal itu, Anda mungkin ingin memverifikasi bahwa argumen adalah nama variabel yang valid terlebih dahulu. Untuk variabel:

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

(catatan yang [[:alpha:]]akan memeriksa karakter alfabet di lokal Anda sementara beberapa shell hanya menerima karakter alfabet dari karakter portabel yang diatur dalam variabel mereka)

Kusalananda
sumber
Tidak ada yang lebih lengkap di dunia ini selain ini. Anda berhak mendapatkan cookie untuk itu.
Karim Manaouil
@KarimManaouil Sepertiga dari kue itu pergi ke Stéphane :-)
Kusalananda