shell 导出磁盘上的bash变量

js4nwp54  于 2023-04-07  发布在  Shell
关注(0)|答案(1)|浏览(117)

我有这样的代码来导出磁盘上的bash变量:

export_to_disk() {
    ### Export variable to disk for later reload
    eval "echo export $1=\"\$$1\"" > $2
    #source $2
}
export_to_disk $mvar file.sh

但是,导出的变量被截断了。如何修复?

nnt7mjpx

nnt7mjpx1#

eval是一个unnecessary source of security risks,强制export意味着你的代码没有正确地保留变量的原始标志(实际上可能会也可能不会导出)。
让shell本身负责序列化变量,使同一shell能够成功地反序列化它:

export_to_disk() {
  declare -p "$1" >"$2"
}

export_to_disk mvar file.sh  # notice mvar not $mvar

...但更聪明的调用约定是将文件名作为 first 参数,因此所有后续参数都被视为变量序列化到该文件中:

export_to_disk() {
  local export_to_disk__filename=$1; shift || return
  declare -p "$@" >"$export_to_disk__filename"
}

export_to_disk file.sh mvar anothervar thirdvar

也就是说,如果你真的想只支持可以导出的字符串类型变量(失去对数组和c的支持),你可以在没有declare -p的情况下做到这一点:

export_to_disk() {
  local export_to_disk__filename=$1; shift || return
  local export_to_disk__varname
  for export_to_disk__varname in "$@"; do
    printf '%s=%q\n; export %q\n' "$export_to_disk__varname" "${!export_to_disk__varname}" "$export_to_disk__varname"
  done
}

让我们把它分解一下:

  • 在这个例子和前面的例子中,都使用了一个以export_to_disk__开头的长变量名来防止冲突:如果我们把它叫做简单的名字,比如var,那么这个程序就不能用来保存一个名为var的变量。使用我们自己的变量命名空间会使这个函数更冗长,但也会使它更强大。
  • 因为我们声明了局部变量,所以我们为自己使用而定义的变量在被调用后不会泄漏到周围的作用域中。
  • 因为我们在将第一个参数赋给变量后使用shift,所以它被从参数列表中删除,所以当我们稍后迭代剩余的参数时,它不再出现在"$@"中。
  • 当我们使用printf %q时,我们正在生成变量值的一个 * 评估安全 * 版本,即使是故意恶意或危险的变量名也可以防止安全问题。(因为我们使用printf %s作为变量 name,不是真正有效的变量名的东西可能会导致生成不安全的代码;因此,如果您正在查找此命令运行的代码,则应确保您信任名称,即使您不信任值)。

相关问题