包含单引号的变量就会消失

时间:2014-08-23 21:05:11

标签: python bash pip

我有一个驱动许多软件包安装的脚本。在一个地方,它使用点子。其中一个软件包需要它自己的构建过程的特殊命令行参数。

pip使安装选项能够传递到构建过程,如下所示:

pip install -U --timeout 30 $ options --install-option =' - hdf5 = / usr / local / hdf5'tables

- install-option是pip的参数。它设置的值--hdf5 = / usr / local / hdf5将被传递给构建过程。因此,单引号必须在那里将所有文本组合为一个遵循等号的参数。您可能会说我可以使用双引号来包围install-option的值。好吧,在命令行我可以。

但是,这是增加的复杂性。这是一个脚本。 pip命令的参数值将传递给数组中的函数。此包的数组条目如下所示:
( “表,PIP ,, - 安装选项= ' - HDF5 =的/ usr /本地/ HDF5'”)

接收函数使用此片段中的set解析数组条目:

IFS=","  # to split apart the pkg array entries

for pkg in "${pkglist[@]}"; do
    set -- ${pkg} 
    if [[ "$2" == "pip" ]]; then  # $1 is pkg, $2 is pip, $3 is url, $4 is options
        DoPip $1 $3 $4
    ...

因此,对于这个软件包,DoPip看到:DoPip表'' - install-option =' - hdf5 = / usr / local / hdf5'

DoPip中出现问题。当我需要运行pip本身时,我无法弄清楚如何扩展最后一个参数。我做了一堆调试,看看会发生什么。会发生什么是3美元的价值被简单地删除 - 它只是消失了。它将以字符串形式回显,但它不会作为命令的一部分工作。

查看功能DoPip。为了帮助调试,我将参数重新分配给显式变量。这没有必要,但有助于确保我没有愚蠢的错误。

DoPip() {

 # run pip command to install packages
    # arguments: 1: package-name 2: optional source <URL>
    #            3: optional pip options
    pkgname=$1
    url=$2
    options=$3

接下来,如果url是非空的,我将变量源设置为pkgname或url。我正在跳过这个片段 - 它有效。

要调试,我回显重新分配的参数:

echo "1. The inbound arguments are: $pkgname $url $options"

输出LOOKS就像它应该工作:

  1. 入站参数为:tables --install-option =' - hdf5 = / usr / local / hdf5'
  2. 这是使用这些参数实际运行pip的语句:

     pip install -U --timeout 30 $options $source
    

    通过调试,这是Bash实际看到和运行的内容:

    + pip install -U --timeout 30 tables
    

    哇! $ options有什么变化?没了!实际上,在此语句之前,我重复回显以验证脚本中间没有任何部分导致值被刷新。不是问题。我可以立即回复$ options的价值 - 没关系。然后,它消失了。

    我无法弄清楚发生了什么或如何做到这一点。我已经尝试了各种方法来转义数组中的单引号,其中最初根据读取非常特殊的单引号创建字符串文字。什么都行不通。整个变量扩张就消失了。

    我尝试过以各种方式进行扩展:

    pip install -U --timeout 30 "$options" $source
    

    这不起作用。选项中的字符串出现但被单引号括起,因此pip命令会引发错误。接下来,我试过了:

    pip install -=U --timeout 30 "${options}" $source
    

    也失败了:单引号和花括号出现,pip再次不高兴。

    --install-options参数是必不可少的。如果没有它,构建就会失败。

    必须有一些方法可以做到这一点。有什么建议吗?

3 个答案:

答案 0 :(得分:0)

$ bash -version
GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

此脚本提供了以下输出:

#!/bin/bash -vx
options=--install-option='--hdf5=/usr/local/hdf5'
source=tables
pip install -U --timeout 30 $options $source


$ ./script.sh 
#!/bin/bash -vx
options=--install-option='--hdf5=/usr/local/hdf5'
+ options=--install-option=--hdf5=/usr/local/hdf5
source=tables
+ source=tables
pip install -U --timeout 30 $options $source
+ pip install -U --timeout 30 --install-option=--hdf5=/usr/local/hdf5 tables
Downloading/unpacking tables
  Downloading tables-3.1.1.tar.gz (6.7MB): 6.7MB downloaded
  Running setup.py (path:/tmp/pip_build_ankur/tables/setup.py) egg_info for package tables
    * Using Python 2.7.3 (default, Feb 27 2014, 19:58:35)
    * Found numpy 1.6.1 package installed.
    .. ERROR:: You need numexpr 2.0.0 or greater to run PyTables!
    Complete output from command python setup.py egg_info:
    * Using Python 2.7.3 (default, Feb 27 2014, 19:58:35)

* Found numpy 1.6.1 package installed.

.. ERROR:: You need numexpr 2.0.0 or greater to run PyTables!

----------------------------------------
Cleaning up...
Command python setup.py egg_info failed with error code 1 in /tmp/pip_build_ankur/tables
Storing debug log for failure in /home/ankur/.pip/pip.log

忽略错误,我看到$ options的值被正确读取并传递给shell。

答案 1 :(得分:0)

所有这些都嵌入在一个非常大的脚本中。我创建了一个较短的版本来专注于这个问题。最后,我采用了一种不同的方法,依赖于环境变量HDF5_DIR而不是pd的cmd线路开关。

显然,你只能做一个或另一个。在任何情况下,在清理过的代码中传递参数,但如果存在环境变量则这是一个错误。去图。

如果有人有兴趣,我会有更短的代码。

当敲头太猛时,远离墙壁,找到另一种方法。我打电话给这个人。

答案 2 :(得分:0)

python包表(也称为potables)的安装程序通过提供给pip的构建开关或通过在开始构建之前设置环境变量来查找hdf5库。在bash脚本中,在开始构建表之前立即创建环境变量更容易/更可靠。没有必要把它放在bash_profile中。环境变量只需要存在于构建表的shell中。安装表后,不再需要环境变量。

在此代码片段中,pkglist是要安装的模块数组,InstallPackages是一个遍历数组并调用相应安装程序的函数:在这种情况下为pip。

    if [[ "$hdf5exists" == "True" ]]; then
        # assert hdf libraries installed
        export HDF5_DIR=/usr/local/hdf5
        pkglist=("${hdf5_pkglist[@]}")  # only install Python wrappers for hdf5
        InstallPackages
    fi

所以,这是我采用的解决方案。