【问题标题】:Exporting an array in bash script在 bash 脚本中导出数组
【发布时间】:2011-07-30 16:22:20
【问题描述】:

我无法将数组从 bash 脚本导出到另一个 bash 脚本,如下所示:

export myArray[0]="Hello"
export myArray[1]="World"

这样写就没有问题了:

export myArray=("Hello" "World")

出于多种原因,我需要将我的数组初始化为多行。你有什么解决办法吗?

【问题讨论】:

  • 如果您执行 bash 或脚本,这两种方法都不起作用,但是如果您获取脚本,则第二种方法将起作用,并且您根本不需要导出。例如:myArray[0]="Hello"; myArray[1]="World" 也可以。

标签: arrays bash export


【解决方案1】:

虽然这个问题/答案已经很老了,但在搜索 "bash serialize array" 时,这篇文章似乎是最热门的

而且,虽然最初的问题完全与序列化/反序列化数组相关,但似乎答案已经朝着这个方向发展。

因此...我提供我的解决方案:

优点
  • 所有核心 Bash 概念
  • 没有评估
  • 没有子命令
缺点
  • 函数将变量名作为参数(相对于实际值)
  • 序列化需要至少有 一个字符出现在数组中

serialize_array.bash

# shellcheck shell=bash

##
# serialize_array
# Serializes a bash array to a string, with a configurable seperator.
#
# $1 = source varname ( contains array to be serialized )
# $2 = target varname ( will contian the serialized string )
# $3 = seperator ( optional, defaults to $'\x01' )
#
# example:
#
#    my_arry=( one "two three" four )
#    serialize_array my_array my_string '|'
#    declare -p my_string
#
# result:
#
#    declare -- my_string="one|two three|four"
#
function serialize_array() {
    declare -n _array="${1}" _str="${2}" # _array, _str => local reference vars
    local IFS="${3:-$'\x01'}"
    # shellcheck disable=SC2034 # Reference vars assumed used by caller
    _str="${_array[*]}" # * => join on IFS
}

##
# deserialize_array
# Deserializes a string into a bash array, with a configurable seperator.
#
# $1 = source varname ( contains string to be deserialized )
# $2 = target varname ( will contain the deserialized array )
# $3 = seperator ( optional, defaults to $'\x01' )
#
# example:
#
#    my_string="one|two three|four"
#    deserialize_array my_string my_array '|'
#    declare -p my_array
#
# result:
#
#    declare -a my_array=([0]="one" [1]="two three" [2]="four")
#
function deserialize_array() {
    IFS="${3:-$'\x01'}" read -r -a "${2}" <<<"${!1}" # -a => split on IFS
}

注意:此处作为要点托管:

[编辑]

  • 通过 shellcheck + shfmt 运行后逻辑简化。
  • 添加了托管 GIST 的 URL

【讨论】:

    【解决方案2】:

    我认为您可以尝试这种方式(在 export 之后采购您的脚本):

    export myArray=(Hello World)

    。 yourScript.sh

    【讨论】:

    • [4 月 28 日星期二 13:21:09 xxx@yyy ~]$ m=(abc def eke);猫/tmp/test.sh; ./tmp/test.sh #!/usr/bin/bash -f # m=() echo "debug +++++++++++ ${#m[@]}" for f in ${米[@]};做回声“=======================> f = $f”;如果 [[ ${#m[@]} -lt 1 ]];然后 echo "error expect more than zeo" else for f in ${m[@]};做回声“-----> f = $f”;完成 fi 调试 +++++++++++ 3 ========================> f = abc ======== ===============> f = def ========================> f = eke ---- -> f = abc -----> f = def -----> f = eke [Tue Apr 28 13:26:29 xxx@yyy ~]$
    • 如果这是您答案的全部内容,您应该edit您的答案并将其全部添加到此处,格式正确。
    • 你试过了吗? myArray 将被解除绑定。
    【解决方案3】:

    我为此编写了自己的函数并使用IFS 改进了该方法:

    特点

    • 不调用$(...),因此不会产生另一个 bash shell 进程
    • ?| 字符序列化为?00?01 序列并返回,因此可以在包含这些字符的数组中使用
    • 将序列化/反序列化之间的行返回字符作为其他字符处理
    • cygwin bash 3.2.48Linux bash 4.3.48 中测试
    function tkl_declare_global()
    {
      eval "$1=\"\$2\"" # right argument does NOT evaluate
    }
    
    function tkl_declare_global_array()
    {
      local IFS=$' \t\r\n' # just in case, workaround for the bug in the "[@]:i" expression under the bash version lower than 4.1
      eval "$1=(\"\${@:2}\")"
    }
    
    function tkl_serialize_array()
    {
      local __array_var="$1"
      local __out_var="$2"
    
      [[ -z "$__array_var" ]] && return 1
      [[ -z "$__out_var" ]] && return 2
    
      local __array_var_size
      eval declare "__array_var_size=\${#$__array_var[@]}"
    
      (( ! __array_var_size )) && { tkl_declare_global $__out_var ''; return 0; }
    
      local __escaped_array_str=''
    
      local __index
      local __value
      for (( __index=0; __index < __array_var_size; __index++ )); do
        eval declare "__value=\"\${$__array_var[__index]}\""
        __value="${__value//\?/?00}"
        __value="${__value//|/?01}"
        __escaped_array_str="$__escaped_array_str${__escaped_array_str:+|}$__value"
      done
    
      tkl_declare_global $__out_var "$__escaped_array_str"
    
      return 0
    }
    
    function tkl_deserialize_array()
    {
      local __serialized_array="$1"
      local __out_var="$2"
    
      [[ -z "$__out_var" ]] && return 1
      (( ! ${#__serialized_array} )) && { tkl_declare_global $__out_var ''; return 0; }
    
      local IFS='|'
      local __deserialized_array=($__serialized_array)
    
      tkl_declare_global_array $__out_var
    
      local __index=0
      local __value
      for __value in "${__deserialized_array[@]}"; do
        __value="${__value//\?01/|}"
        __value="${__value//\?00/?}"
        tkl_declare_global $__out_var[__index] "$__value"
        (( __index++ ))
      done
    
      return 0
    }
    

    例子:

    a=($'1 \n 2' "3\"4'" 5 '|' '?')
    tkl_serialize_array a b
    tkl_deserialize_array "$b" c
    

    【讨论】:

    • 这很有趣。但是,尚不清楚如何使用它,因为您的示例没有任何 cmets,也没有引用 tkl_declare_global()tkl_declare_global_array()。请问您有机会扩展这个答案吗?
    • @MikeSchinkel 不确定您的意思是“参考”。这两个函数都在 sn-p 中。
    • Andry — 让我重述这个问题。根据您的示例,我不明白如何使用函数。我认为自己在 Bash 中几乎没有中级,因此对于经验丰富的 Bash 开发人员来说,如何使用它们可能非常明显。但对我——可能还有其他许多努力学习 Bash 的人来说——并没有那么多。 :-(。我想知道您是否介意详细说明这些函数在实践中的实际使用方式以及更详细的示例?提前谢谢您。
    • @MikeSchinkel 我不能在这里详细说明比答案中的更多细节。这些 cmets 的性质不是为了这个目的。但是,我可能会建议打开一个频道来讨论那里的细节。可以在这里完成,但由于某种原因我无法创建它(没有这样的按钮)。在我的工作中,我使用它将数组作为字符串从进程传递到另一个进程,因为 bash 数组非常不可移植,并且不能作为数组通过任何任意进程的边界,除非仅作为环境细绳。所以我使用转换来实现它。
    【解决方案4】:

    环境只是键值对的集合,两者都是字符串。适用于任何类型数组的适当解决方案也可以

    • 将每个元素保存在不同的变量中(例如 MY_ARRAY_0=myArray[0])。由于dynamic variable names 而变得复杂。
    • 将数组保存在文件系统中(声明 -p myArray >file)。
    • 将所有数组元素序列化为一个字符串。

    这些在其他帖子中都有介绍。如果您知道您的值从不包含某个字符(例如 |)并且您的键是连续整数,您可以简单地将数组保存为分隔列表:

    export MY_ARRAY=$(IFS='|'; echo "${myArray[*]}")
    

    并在子进程中恢复:

    IFS='|'; myArray=($MY_ARRAY); unset IFS
    

    【讨论】:

    • 尽管它正确处理了换行符,但它不处理| 字符本身。您必须在完全恢复数组之前和之后对该字符进行预处理。
    • @Andry 没错。正如我所说,这个解决方案只有在你知道你的值从不包含某些字符的情况下才有效。在示例中,我假设这些值从不包含 | 字符,它可以用作分隔符。
    【解决方案5】:

    天哪。我不知道为什么其他答案使这变得如此复杂。 Bash 几乎内置了对此的支持。

    在导出脚本中:

    myArray=( '  foo"bar  ' $'\n''\nbaz)' )  # an array with two nasty elements
    
    myArray="${myArray[@]@Q}" ./importing_script.sh
    

    (注意,双引号对于正确处理数组元素中的空格是必需的。)

    进入importing_script.sh 时,myArray 环境变量的值包含这 26 个字节:

    '  foo"bar  ' $'\n\\nbaz)'
    

    那么下面将重构数组:

    eval "myArray=( ${myArray} )"
    

    注意! 如果您不能信任myArray 环境变量的来源,请不要像这样eval。这个技巧展示了"Little Bobby Tables" 漏洞。想象一下,如果有人将myArray 的值设置为) ; rm -rf / #

    【讨论】:

    • 我认为eval 是一个危险的功能,不应该在脚本中使用。
    • @jww: eval is 如果您不能确定正在评估的字符串的内容,则很危险。阅读我上面的注意
    • 好的,这将删除阵列功能。最简单的工作解决方案不是启动新的 shell,而是在当前 shell 的上下文中执行脚本:stackoverflow.com/questions/8352851/… using source othershellscript
    • @dothebart:“删除数组功能”是什么意思?按照我的建议,子进程中的myArray shell 变量将保存一个与父进程中的myArray shell 变量相同的数组。 (也许您忽略了eval 语句中的括号?)
    • 使用A 运算符代替Q 怎么样?使用myArray="${myArray[@]@A}" ./importing_script.sh,然后在脚本中简单地使用eval "$myArray"
    【解决方案6】:

    基于@mr.spuratic 使用BASH_ENV,这里我通过script -f -c 隧道$@

    script -c &lt;command&gt; &lt;logfile&gt; 可用于在另一个 pty(和进程组)内运行命令,但它不能将任何结构化参数传递给 &lt;command&gt;

    &lt;command&gt; 是一个简单的字符串,可以作为system 库调用的参数。

    我需要将外部 bash 的 $@ 隧道连接到脚本调用的 bash 的 $@

    由于declare -p 不能使用@,所以我在这里使用魔法 bash 变量_(带有一个虚拟的第一个数组值,因为它会被 bash 覆盖)。这让我免于践踏任何重要的变量:

    概念证明: BASH_ENV=&lt;( declare -a _=("" "$@") &amp;&amp; declare -p _ ) bash -c 'set -- "${_[@]:1}" &amp;&amp; echo "$@"'

    “但是,”你说,“你正在向 bash 传递参数——我确实是这样,但这些是一个简单的已知字符字符串。这是 script 使用的

    SHELL=/bin/bash BASH_ENV=&lt;( declare -a _=("" "$@") &amp;&amp; declare -p _ &amp;&amp; echo 'set -- "${_[@]:1}"') script -f -c 'echo "$@"' /tmp/logfile

    这给了我这个包装函数in_pty:

    in_pty() { SHELL=/bin/bash BASH_ENV=<( declare -a _=("" "$@") && declare -p _ && echo 'set -- "${_[@]:1}"') script -f -c 'echo "$@"' /tmp/logfile }

    或者这个无函数包装器作为 Makefiles 的可组合字符串:

    in_pty=bash -c 'SHELL=/bin/bash BASH_ENV=&lt;( declare -a _=("" "$$@") &amp;&amp; declare -p _ &amp;&amp; echo '"'"'set -- "$${_[@]:1}"'"'"') script -qfc '"'"'"$$@"'"'"' /tmp/logfile' --

    ...

    $(in_pty) test --verbose $@ $^

    【讨论】:

      【解决方案7】:

      非常感谢@stéphane-chazelas 指出了我之前尝试的所有问题,现在这似乎可以将数组序列化为标准输出或变量。

      这种技术不会对输入进行 shell 解析(与 declare -a/declare -p 不同),因此可以安全地防止在序列化文本中恶意插入元字符。

      注意:换行符不会转义,因为read 删除了\&lt;newlines&gt; 字符对,所以必须将-d ... 传递给读取,然后保留未转义的换行符。

      所有这些都在unserialise 函数中进行管理。

      使用了两个魔术字符,字段分隔符和记录分隔符(这样多个数组可以序列化到同一个流中)。

      这些字符可以定义为FSRS,但都不能定义为newline 字符,因为read 删除了转义的换行符。

      转义字符必须是\ 反斜杠,因为read 使用它来避免字符被识别为IFS 字符。

      serialise"$@" 序列化为标准输出,serialise_to 将序列化为$1 中命名的变量

      serialise() {
        set -- "${@//\\/\\\\}" # \
        set -- "${@//${FS:-;}/\\${FS:-;}}" # ; - our field separator
        set -- "${@//${RS:-:}/\\${RS:-:}}" # ; - our record separator
        local IFS="${FS:-;}"
        printf ${SERIALIZE_TARGET:+-v"$SERIALIZE_TARGET"} "%s" "$*${RS:-:}"
      }
      serialise_to() {
        SERIALIZE_TARGET="$1" serialise "${@:2}"
      }
      unserialise() {
        local IFS="${FS:-;}"
        if test -n "$2"
        then read -d "${RS:-:}" -a "$1" <<<"${*:2}"
        else read -d "${RS:-:}" -a "$1"
        fi
      }
      

      反序列化:

      unserialise data # read from stdin
      

      unserialise data "$serialised_data" # from args
      

      例如

      $ serialise "Now is the time" "For all good men" "To drink \$drink" "At the \`party\`" $'Party\tParty\tParty'
      Now is the time;For all good men;To drink $drink;At the `party`;Party   Party   Party:
      

      (没有尾随换行符)

      回读:

      $ serialise_to s "Now is the time" "For all good men" "To drink \$drink" "At the \`party\`" $'Party\tParty\tParty'
      $ unserialise array "$s"
      $ echo "${array[@]/#/$'\n'}"
      
      Now is the time 
      For all good men 
      To drink $drink 
      At the `party` 
      Party   Party   Party
      

      unserialise array # read from stdin
      

      Bash 的 read 尊重转义字符 \(除非您传递 -r 标志)以删除字符的特殊含义,例如输入字段分隔或行分隔符。

      如果你想序列化一个数组而不是一个参数列表,那么只需将你的数组作为参数列表传递:

      serialise_array "${my_array[@]}"
      

      您可以像使用 read 一样在循环中使用 unserialise,因为它只是一个包装读取 - 但请记住,流不是换行符分隔的:

      while unserialise array
      do ...
      done
      

      【讨论】:

        【解决方案8】:

        对于值没有空格的数组,我一直在使用一组简单的函数来遍历每个数组元素并连接数组:

        _arrayToStr(){
            array=($@)
        
            arrayString=""
            for (( i=0; i<${#array[@]}; i++ )); do
                if [[ $i == 0 ]]; then
                    arrayString="\"${array[i]}\""
                else
                    arrayString="${arrayString} \"${array[i]}\""
                fi
            done
        
            export arrayString="(${arrayString})"
        }
        
        _strToArray(){
            str=$1
        
            array=${str//\"/}
            array=(${array//[()]/""})
        
            export array=${array[@]}
        }
        

        第一个函数通过添加左括号和右括号并转义所有双引号将数组转换为字符串。第二个函数将去掉引号和括号并将它们放入一个虚拟数组中。

        为了导出数组,你需要传入原始数组的所有元素:

        array=(foo bar)
        _arrayToStr ${array[@]}
        

        此时,数组已导出为值$arrayString。要在目标文件中导入数组,请重命名数组并进行相反的转换:

        _strToArray "$arrayName"
        newArray=(${array[@]})
        

        【讨论】:

          【解决方案9】:

          TL;DR:直接不支持可导出数组,直到 bash-4.3(包括 bash-4.3),但您可以(有效)通过以下两种方式之一导出数组:

          • 对子脚本调用方式的简单修改
          • 使用导出的函数来存储数组初始化,只需对子脚本进行简单修改

          或者,您可以等到 bash-4.3 发布(截至 2014 年 2 月处于开发/RC 状态,请参阅变更日志中的 ARRAY_EXPORT)。 更新:此功能不是 em> 在 4.3 中启用。如果在构建时定义ARRAY_EXPORT,构建将失败。作者has stated不打算完成这个功能。


          首先要了解的是 bash 环境(更准确地说是command execution environment)与 POSIX 环境概念不同。 POSIX environment 是无类型的name=value 对的集合,可以从进程传递给它的子进程in various ways(实际上是IPC 的有限形式)。

          bash 执行环境实际上是它的超集,具有类型变量、只读和可导出标志、数组、函数等。这部分解释了为什么set(bash 内置)和envprintenv 的输出不同。

          当您调用另一个 bash shell 时,您正在启动一个新进程,您会失去一些 bash 状态。但是,如果您对脚本进行点源,则该脚本将在相同的环境中运行;或者,如果您通过( ) 运行子shell,环境也会被保留(因为 bash 分叉,保留其完整状态,而不是使用进程环境重新初始化)。


          @lesmana 的答案中引用的限制出现了,因为 POSIX 环境只是 name=value 对,没有额外的含义,因此没有一致的方法来编码或格式化类型变量,请参阅下面关于函数 的有趣 bash 怪癖,以及 bash-4.3 中即将发生的变化(放弃了提议的数组功能)。

          有几种简单的方法可以做到这一点,使用declare -p(内置)将一些bash环境输出为一组一个或多个declare语句,可用于重建类型和值一个名字”。这是基本的serialisation,但其他一些答案暗示的complexity 却少得多。 declare -p 保留数组索引、稀疏数组和麻烦值的引用。对于数组的简单序列化,您可以逐行转储值,然后使用 read -a myarray 来恢复它(适用于连续的 0 索引数组,因为 read -a 自动分配索引)。

          这些方法不需要对您将数组传递到的脚本进行任何修改。

          declare -p array1 array2 > .bash_arrays       # serialise to an intermediate file
          bash -c ". .bash_arrays; . otherscript.sh"    # source both in the same environment
          

          上述bash -c "..." 形式的变体有时(错误)在 crontab 中用于设置变量。

          替代方案包括:

          declare -p array1 array2 > .bash_arrays       # serialise to an intermediate file
          BASH_ENV=.bash_arrays otherscript.sh          # non-interactive startup script
          

          或者,作为单行:

          BASH_ENV=<(declare -p array1 array2) otherscript.sh
          

          最后一个使用进程替换declare命令的输出作为rc脚本传递。 (此方法仅适用于 bash-4.0 或更高版本:早期版本无条件 fstat() rc 文件,并一次性使用返回到 read() 文件的大小;FIFO 返回大小为 0,因此不能作为希望。)

          非交互式 shell(即 shell 脚本)中,BASH_ENV 变量指向的文件是 automatically sourced。您必须确保正确调用 bash,可能使用 shebang 显式调用“bash”,而不是 #!/bin/sh,因为 bash 在历史/POSIX 模式下将不支持 BASH_ENV

          如果您的所有数组名称碰巧有一个共同的前缀,您可以使用declare -p ${!myprefix*} 来展开它们的列表,而不是枚举它们。

          您可能不应该尝试使用此方法导出和重新导入 整个 bash 环境,一些特殊的 bash 变量和数组是只读的,修改时可能会有其他副作用特殊变量。

          (您也可以通过将数组定义序列化为可导出变量并使用eval 来做一些稍微不愉快的事情,但我们不鼓励使用eval ...

          $ array=([1]=a [10]="b c")
          $ export scalar_array=$(declare -p array)
          $ bash # start a new shell
          $ eval $scalar_array
          $ declare -p array
          declare -a array='([1]="a" [10]="b c")'
          

          )


          如上所述,有一个有趣的怪癖:通过环境导出函数的特殊支持:

          function myfoo() {
              echo foo
          }
          

          使用export -fset +a 启用此行为,将在(进程)环境中导致此行为,使用printenv 可见:

          myfoo=() { echo foo
          }
          

          变量为functionname(或functioname(),用于向后兼容),其值为() { functionbody }。 当后续的 bash 进程启动时,它将从每个这样的环境变量重新创建一个函数。如果您查看 bash-4.2 源文件 variables.c,您会看到以 () { 开头的变量是经过特殊处理的。 (尽管禁止使用 declare -f 的这种语法创建函数。)更新:shellshock" 安全问题与此功能有关,现代系统可能会禁用从环境中自动导入函数作为缓解。

          如果你继续阅读,你会看到一个#if 0(或#if ARRAY_EXPORT)保护代码,它检查以([ 开头并以) 结尾的变量,以及一条说明“数组变量”的注释可能尚未导出”。 好消息是,在当前开发版本 bash-4.3rc2 中,导出索引数组(非关联)的功能启用。此功能不太可能启用,如上所述。

          我们可以使用它来创建一个函数来恢复所需的任何数组数据:

          % function sharearray() {
              array1=(a b c d)
          }
          
          % export -f sharearray 
          
          % bash -c 'sharearray; echo ${array1[*]}'
          

          因此,与之前的方法类似,调用子脚本:

          bash -c "sharearray; . otherscript.sh"
          

          或者,您可以通过在某个适当的点添加来有条件地调用子脚本中的sharearray 函数:

          [ "`type -t sharearray`" = "function" ] && sharearray
          

          请注意,sharearray 函数中没有 declare -a,如果您这样做,该数组对于函数是隐式的本地,这不是我们想要的。 bash-4.2 支持declare -g,它显式地使变量成为全局变量,这样就可以使用 (declare -ga)。 (由于关联数组 require declare -A 在 bash-4.2 之前,您将无法将此方法用于关联数组。)GNU parallel 文档对此方法有有用的变化,请参阅在man page 中讨论--env


          您的问题也表明您可能对export 本身有问题。您可以在创建或修改名称后导出它。 “可导出”是变量的标志或属性,为方便起见,您还可以在单​​个语句中设置和导出。最高 bash-4.2 export 只需要一个名称,支持简单(标量)变量或函数名称。

          即使您可以(将来)导出数组,也可能不支持导出选定的索引(切片)(尽管由于数组是稀疏的,因此没有理由不允许这样做)。虽然 bash 也支持 declare -a name[0] 语法,但忽略了下标,“name”只是一个普通的索引数组。

          【讨论】:

            【解决方案10】:

            数组变量可能(尚未)被导出。

            来自 ubuntu 10.04 下 bash 版本 4.1.5 的手册页。

            来自 Chet Ramey(截至 2011 年的当前 bash 维护者)的以下声明可能是有关此“错误”的最官方文档:

            实际上没有一种将数组变量编码到环境中的好方法。

            http://www.mail-archive.com/bug-bash@gnu.org/msg01774.html

            【讨论】:

            • 奇怪,bash reference 没有提到这个
            • 呃...对于 bash 所做的所有事情,它无法导出数组供其他脚本使用...
            • 您无法导出数组,原因与您首先需要数组的原因相同:您无法在不丢失数组结构的情况下安全地将数组展平为单个以 null 分隔的字符串。跨度>
            【解决方案11】:

            正如 lesmana 所报告的,您无法导出数组。因此,您必须在通过环境之前对它们进行序列化。这种序列化在仅适合字符串的其他地方也很有用(su -c 'string',ssh host 'string')。执行此操作的最短代码方法是滥用 'getopt'

            # preserve_array(arguments). return in _RET a string that can be expanded
            # later to recreate positional arguments. They can be restored with:
            #   eval set -- "$_RET"
            preserve_array() {
                _RET=$(getopt --shell sh --options "" -- -- "$@") && _RET=${_RET# --}
            }
            
            # restore_array(name, payload)
            restore_array() {
               local name="$1" payload="$2"
               eval set -- "$payload"
               eval "unset $name && $name=("\$@")"
            }
            

            像这样使用它:

            foo=("1: &&& - *" "2: two" "3: %# abc" )
            preserve_array "${foo[@]}"
            foo_stuffed=${_RET}
            restore_array newfoo "$foo_stuffed"
            for elem in "${newfoo[@]}"; do echo "$elem"; done
            
            ## output:
            # 1: &&& - *
            # 2: two
            # 3: %# abc
            

            这不解决未设置/稀疏数组。 您也许可以减少 restore_array 中的 2 个“eval”调用。

            【讨论】:

              【解决方案12】:

              我正在编辑另一篇帖子并犯了一个错误。啊。无论如何,也许这可能会有所帮助? https://stackoverflow.com/a/11944320/1594168

              请注意,由于 shell 的数组格式在 bash 或任何其他 shell 端没有记录, 以独立于平台的方式返回一个 shell 数组是非常困难的。 您必须检查版本,并制作一个简单的脚本来连接所有 将 shell 数组放入其他进程可以解析到的文件中。

              但是,如果你知道要带回家的阵列的名称,那么有办法,虽然有点脏。

              假设我有

              MyAry[42]="whatever-stuff";
              MyAry[55]="foo";
              MyAry[99]="bar";
              

              所以我想把它带回家

              name_of_child=MyAry
              take_me_home="`declare -p ${name_of_child}`";
              export take_me_home="${take_me_home/#declare -a ${name_of_child}=/}"
              

              我们可以通过检查子进程看到它正在导出

              echo ""|awk '{print "from awk =["ENVIRON["take_me_home"]"]";  }'
              

              结果:

              from awk =['([42]="whatever-stuff" [55]="foo" [99]="bar")']
              

              如果我们绝对必须,请使用 env var 转储它。

              env > some_tmp_file
              

              然后

              在运行另一个脚本之前,

              # This is the magic that does it all
              source some_tmp_file
              

              【讨论】:

              • declare -p 丢失换行符。
              【解决方案13】:

              你(嗨!)可以使用这个,不需要写文件,对于 ubuntu 12.04,bash 4.2.24

              另外,您的多行数组可以导出。

              cat >>exportArray.sh

              function FUNCarrayRestore() {
                  local l_arrayName=$1
                  local l_exportedArrayName=${l_arrayName}_exportedArray
              
                  # if set, recover its value to array
                  if eval '[[ -n ${'$l_exportedArrayName'+dummy} ]]'; then
                      eval $l_arrayName'='`eval 'echo $'$l_exportedArrayName` #do not put export here!
                  fi
              }
              export -f FUNCarrayRestore
              
              function FUNCarrayFakeExport() {
                  local l_arrayName=$1
                  local l_exportedArrayName=${l_arrayName}_exportedArray
              
                  # prepare to be shown with export -p
                  eval 'export '$l_arrayName
                  # collect exportable array in string mode
                  local l_export=`export -p \
                      |grep "^declare -ax $l_arrayName=" \
                      |sed 's"^declare -ax '$l_arrayName'"export '$l_exportedArrayName'"'`
                  # creates exportable non array variable (at child shell)
                  eval "$l_export"
              }
              export -f FUNCarrayFakeExport
              

              在终端 bash 上测试此示例(适用于 bash 4.2.24):

              source exportArray.sh
              list=(a b c)
              FUNCarrayFakeExport list
              bash
              echo ${list[@]} #empty :(
              FUNCarrayRestore list
              echo ${list[@]} #profit! :D
              

              我可能会改进它here

              PS.:如果有人清除/改进/makeItRunFaster 我想知道/看看,谢谢! :D

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-07-11
                • 2013-01-01
                • 1970-01-01
                相关资源
                最近更新 更多