bash - 不污染自己的命名空间的源代码

bash - 不污染自己的命名空间的源代码

我想将另一个 bash 脚本的变量内容分配给调用脚本中的变量。

具体来说,我source这个文件:https://projects.archlinux.org/svntogit/packages.git/plain/trunk/PKGBUILD?h=packages/firefox(以及其他类似文件)。

该文件包含名为dependsmakedepends等的变量。

所以在我的脚本中我有多个这样的语句:

depends="$(source "/path/to/file" ; printf '%s' "${depends[@]}")"
makedepends="$(source "/path/to/file" ; printf '%s' "${makedepends[@]}")"
...

所以基本上,每个语句都会启动它自己的子 shell,该子 shell 获取文件并打印内容只有一个变量到父 shell 中的变量。

是否有另一种方法涉及启动单个子 shell,获取文件并获取分配给调用 shell 中指定变量的文件的指定变量的内容不污染调用shell的环境?

-------------------------------------------------- ----------------------

由于马克·曼指出了使用外国脚本的危险source,我最终提出了另一个解决方案。您可以使用带有正则表达式的source多行来从文件中 grep 所有需要的变量,而不是使用它来获取另一个脚本的变量 (varName=(...),varName2="...",varname3='... ',varName4=...) 和结果:grepperleval

$ grepvars='(license)|(depends)|(makedepends)|(url)|(pkgdesc)|(pkgver)'
$
$ eval $(grep -Pzo "^(${grepvars})=\([^\)\(\`]*\)|^(${grepvars})=\"[^\"\(\`]*\"|^(${grepvars})='\''[^'\'']*'\''|^(${grepvars})=[^\s;\(\`]*" /tmp/above_mentioned_file)
$ echo $url
https://www.mozilla.org/firefox/
$
$ echo ${depends[@]}
gtk3 gtk2 mozilla-common libxt startup-notification mime-types dbus-glib alsa-lib ffmpeg2.8 desktop-file-utils hicolor-icon-theme libvpx icu libevent nss hunspell sqlite ttf-font

答案1

使用eval

如果您有源代码(在 /tmp/other.sh 中):

a=1
b=2
c=3

如果您只需要一部分,您可以使用它eval来获取这些项目(在 /tmp/main.sh 中):

eval $(source /tmp/other.sh;
       echo a="$a";
       echo b="$b";)

echo a is $a "(expect 1)"
echo b is $b "(expect 2)"
echo c is $c "(expect nothing)"

并运行它:

$ bash /tmp/main.sh
a is 1 (expect 1)
b is 2 (expect 2)
c is (expect nothing)

警告:对不受信任的脚本执行evalorsource是非常危险的。您正在执行一个 shell 脚本,并且该脚本可以执行您自己可以执行的任何操作。警告

答案2

如果您正在使用或类似的方法,在不使用的情况eval下,您仍然可以通过进程替换来执行此操作:bash

source <(source "/path/to/file" ; printf %s\\n "depends=${depends[*]}" "makedepends=${makedepends[*]}")

这将启动一个子 shell 并获取文件,就像您的初始示例一样,但它不是直接打印值并使用命令替换,而是打印格式化为赋值的值并使用进程替换获取输出。

这完全回答了您问题的以下部分:

是否有另一种方法涉及启动单个子 shell、获取文件并获取分配给调用 shell 中指定变量的文件的指定变量的内容,而不污染调用 shell 的环境?

但是当然采购外国剧本的危险仍然存在。永远不要获取不受信任的脚本。

如果您自己编写了脚本并且您是绝对确定它没有副作用(并且不产生输出)那么你可以使用上面的你自己的个人电脑。这不是应该的事情曾经在制作脚本中。非常非常大的安全漏洞。

答案3

source <(cat "/path/to/file" | grep "depends\|makedepends")

根本/path/to/file没有来源(与通配符的方法相比)。请参阅上面关于不安全感的讨论。此外,如果是,例如.envfile ofdocker-compose或类似文件,则可以通过其他脚本以这样的方式使用它来绘制变量,而不执行未加引号的变量,这些变量可能会导致执行错误。例如 -traefik像这样的前端规则,WEB_FRONTEND_RULE=Host:my.host.name;PathPrefix:/my-path-prefix在 中有效,docker-compose .env但在 中来源无效bash。并且WEB_FRONTEND_RULE='Host:my.host.name;PathPrefix:/my-path-prefix'对于源自 有效bash,但在 中无效docker-compose .env

答案4

扩展于回答从通配符,并在获取文件之后(所有相同的警告只有在您相信文件),我们可以通过扫描来识别导出的变量名称,获取它们的声明并重新导出它们。

source-export() {
  local _RC=0
  local FILENAME=$1
  shift
  source <(
    source "${FILENAME}" "$@"
    _RC=$?
    if (( _RC )); then
      typeset -p _RC
      exit
    fi
    # show the exported names
    PATTERN="\b(?<=export)(\s+\w+)+"
    while read -r NAME; do
      [[ -n ${NAME} ]] && typeset -p "${NAME}"
    done < <(grep -oP "${PATTERN}" "${FILENAME}" | tr ' ' '\n')
  )
  return ${_RC}
}

注意:我们用来扫描导出的模式应该相当稳健(处理类似的情况export A B)。另一种可能更稳健的方法是在导出变量的采购前后区分变量表。

例子:

$ cat foo.sh
export XXX="432"
YYY=111
export ZZZ="'adfa $*"
export A B
A=1
B=2
C=3

$ source-export foo.sh 3 2 1
$ echo -e "XXX=$XXX\nYYY=$YYY\nZZZ=$ZZZ\nA=$A\nB=$B\nC=$C"
XXX=432
YYY=
ZZZ='adfa 3 2 1
A=1
B=2
C=

相对:

$ source foo.sh 3 2 1
$ echo -e "XXX=$XXX\nYYY=$YYY\nZZZ=$ZZZ\nA=$A\nB=$B\nC=$C"
XXX=432
YYY=111
ZZZ='adfa 3 2 1
A=1
B=2
C=3

bash和上进行了测试zsh

相关内容