在 bash 脚本中导出数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5564418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Exporting an array in bash script
提问by Remiii
I can not export an array from a bash script to another bash script like this:
我无法将数组从 bash 脚本导出到另一个 bash 脚本,如下所示:
export myArray[0]="Hello"
export myArray[1]="World"
When I write like this there are no problem:
当我这样写时,没有问题:
export myArray=("Hello" "World")
For several reasons I need to initialize my array into multiple lines. Do you have any solution?
出于多种原因,我需要将数组初始化为多行。你有什么解决办法吗?
采纳答案by lesmana
Array variables may not (yet) be exported.
数组变量可能(尚未)导出。
From the manpage of bash version 4.1.5 under ubuntu 10.04.
来自 ubuntu 10.04 下 bash 版本 4.1.5 的联机帮助页。
The following statement from Chet Ramey (current bash maintainer as of 2011) is probably the most official documentation about this "bug":
Chet Ramey(截至 2011 年的当前 bash 维护者)的以下声明可能是关于此“错误”的最官方文档:
There isn't really a good way to encode an array variable into the environment.
将数组变量编码到环境中并没有真正的好方法。
回答by mr.spuratic
TL;DR:exportable arrays are not directlysupported up to and including bash-4.3, but you can (effectively) export arrays in one of two ways:
TL;DR:不直接支持可导出数组,包括 bash-4.3,但您可以(有效)通过以下两种方式之一导出数组:
- a simple modification to the way the child scripts are invoked
- use an exported functionto store the array initialisation, with a simple modification to the child scripts
- 对子脚本调用方式的简单修改
- 使用导出的函数来存储数组初始化,对子脚本进行简单的修改
Or, you can wait until bash-4.3 is released (in development/RC state as of February 2014, see ARRAY_EXPORT in the Changelog).Update: This feature is notenabled in 4.3. If you define ARRAY_EXPORT
when building, the build will fail. The author has statedit is not planned to complete this feature.
或者,您可以等到 bash-4.3 发布(截至 2014 年 2 月处于开发/RC 状态,请参阅更新日志中的 ARRAY_EXPORT)。更新:此功能在 4.3 中未启用。如果ARRAY_EXPORT
在构建时定义,构建将失败。作者已声明不计划完成此功能。
The first thing to understand is that the bash environment (more properly command execution environment) is different to the POSIX concept of an environment. The POSIX environmentis a collection of un-typed name=value
pairs, and can be passed from a process to its children in various ways(effectively a limited form of IPC).
首先要了解的是 bash 环境(更恰当地说是命令执行环境)不同于 POSIX 环境的概念。该POSIX环境是无类型的集合name=value
对,并可以从它的孩子的过程来通过各种方式(有效限量表IPC)。
The bash execution environment is effectively a superset of this, with typed variables, read-only and exportable flags, arrays, functions and more. This partly explains why the output of set
(bash builtin) and env
or printenv
differ.
bash 执行环境实际上是它的超集,具有类型化变量、只读和可导出标志、数组、函数等。这部分解释了为什么set
(bash builtin) and env
or的输出printenv
不同。
When you invokeanother bash shell you're starting a new process, you loose some bash state. However, if you dot-source a script, the script is run in the same environment; or if you run a subshell via ( )
the environment is also preserved (because bash forks, preserving its complete state, rather than reinitialising using the process environment).
当您调用另一个 bash shell 时,您正在启动一个新进程,您会丢失一些 bash 状态。但是,如果您点源脚本,则该脚本将在相同的环境中运行;或者,如果您通过( )
环境运行子shell,也会保留(因为 bash 分叉,保留其完整状态,而不是使用进程环境重新初始化)。
The limitation referenced in @lesmana's answer arises because the POSIX environment is simply name=value
pairs with no extra meaning, so there's no agreed way to encode or format typed variables, see below for an interesting bash quirk regarding functions , and an upcoming change in bash-4.3(proposed array feature abandoned).
@lesmana 的回答中提到的限制是因为 POSIX 环境只是name=value
成对的,没有额外的意义,所以没有商定的方式来编码或格式化类型变量,请参阅下面关于函数的有趣 bash 怪癖,以及即将到来的 bash-4.3 变化(建议的阵列功能已放弃)。
There are a couple of simple ways to do this using declare -p
(built-in) to output some of the bash environment as a set of one or more declare
statements which can be used reconstruct the type and value of a "name". This is basic serialisation, but with rather less of the complexitysome of the other answers imply. declare -p
preserves array indexes, sparse arrays and quoting of troublesome values. For simple serialisation of an array you could just dump the values line by line, and use read -a myarray
to restore it (works with contiguous 0-indexed arrays, since read -a
automatically assigns indexes).
有几种简单的方法可以使用declare -p
(内置)将一些 bash 环境输出为一组一个或多个declare
语句,这些语句可用于重建“名称”的类型和值。这是基本的序列化,但其他一些答案暗示的复杂性要低得多。declare -p
保留数组索引、稀疏数组和麻烦值的引用。对于数组的简单序列化,您可以逐行转储值,并用于read -a myarray
恢复它(适用于连续的 0 索引数组,因为会read -a
自动分配索引)。
These methods do not require any modification of the script(s) you are passing the arrays to.
这些方法不需要对您将数组传递到的脚本进行任何修改。
declare -p array1 array2 > .bash_arrays # serialise to an intermediate file
bash -c ". .bash_arrays; . otherscript.sh" # source both in the same environment
Variations on the above bash -c "..."
form are sometimes (mis-)used in crontabs to set variables.
bash -c "..."
有时(错误地)在 crontab 中使用上述形式的变体来设置变量。
Alternatives include:
替代方案包括:
declare -p array1 array2 > .bash_arrays # serialise to an intermediate file
BASH_ENV=.bash_arrays otherscript.sh # non-interactive startup script
Or, as a one-liner:
或者,作为单线:
BASH_ENV=<(declare -p array1 array2) otherscript.sh
The last one uses process substitutionto pass the output of the declare
command as an rc script. (This method only works in bash-4.0 or later: earlier versions unconditionally fstat()
rc files and use the size returned to read()
the file in one go; a FIFO returns a size of 0, and so won't work as hoped.)
最后一个使用进程替换将declare
命令的输出作为 rc 脚本传递。(此方法仅适用于 bash-4.0 或更高版本:早期版本无条件地fstat()
rc 文件并使用一次返回到read()
文件的大小;FIFO 返回大小为 0,因此不会按预期工作。)
In a non-interactive shell(i.e. shell script) the file pointed to by the BASH_ENV
variable is automatically sourced. You must make sure bash is correctly invoked, possibly using a shebang to invoke "bash" explicitly, and not #!/bin/sh
as bash will not honour BASH_ENV
when in historical/POSIX mode.
在非交互式 shell(即 shell 脚本)中,BASH_ENV
变量指向的文件是自动获取的。您必须确保 bash 被正确调用,可能使用 shebang 显式调用“bash”,而不是#!/bin/sh
因为 bashBASH_ENV
在历史/POSIX 模式下不会兑现。
If all your array names happen to have a common prefix you can use declare -p ${!myprefix*}
to expand a list of them, instead of enumerating them.
如果您的所有数组名称碰巧都有一个公共前缀,您可以使用它declare -p ${!myprefix*}
来扩展它们的列表,而不是枚举它们。
You probably should not attempt to export and re-import the entirebash environment using this method, some special bash variables and arrays are read-only, and there can be other side-effects when modifying special variables.
您可能不应该尝试使用这种方法导出和重新导入整个bash 环境,一些特殊的 bash 变量和数组是只读的,并且在修改特殊变量时可能会有其他副作用。
(You could also do something slightly disagreeable by serialising the array definition to an exportable variable, and using eval
, but let's not encourage the use of eval
...
(您也可以通过将数组定义序列化为可导出变量并使用 来做一些稍微令人不快的事情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")'
)
)
As referenced above, there's an interesting quirk: special support for exporting functions through the environment:
如上所述,有一个有趣的怪癖:通过环境导出函数的特殊支持:
function myfoo() {
echo foo
}
with export -f
or set +a
to enable this behaviour, will result in this in the (process) environment, visible with printenv
:
使用export -f
或set +a
启用此行为,将在(进程)环境中导致此行为,可见printenv
:
myfoo=() { echo foo
}
The variable is functionname
(or functioname()
for backward compatibility) and its value is () { functionbody }
.
When a subsequent bash process starts it will recreate a function from each such environment variable. If you peek into the bash-4.2 source file variables.c
you'll see variables starting with () {
are handled specially. (Though creating a function using this syntax with declare -f
is forbidden.) Update:The "shellshock"security issue is related to this feature, contemporary systems may disable automatic function import from the environment as a mitigation.
变量是functionname
(或functioname()
为了向后兼容),其值为() { functionbody }
。当后续的 bash 进程启动时,它将从每个这样的环境变量中重新创建一个函数。如果您查看 bash-4.2 源文件,variables.c
您会看到以 开头的变量() {
是经过特殊处理的。(虽然declare -f
禁止使用此语法创建函数 with 。)更新:“ shellshock”安全问题与此功能有关,当代系统可能会禁用从环境中自动导入函数作为缓解措施。
If you keep reading though, you'll see an #if 0
(or #if ARRAY_EXPORT
) guarding code that checks variables starting with ([
and ending with )
, and a comment stating "Array variables may not yet be exported". The good news is that in the current development version bash-4.3rc2 the ability to export indexed arrays (not associative) isenabled.This feature is not likely to be enabled, as noted above.
如果您继续阅读,您将看到一个#if 0
(或#if ARRAY_EXPORT
)保护代码,该代码检查以 开头([
和结尾的变量)
,以及一条说明“数组变量可能尚未导出”的注释。好消息是在当前的开发版本 bash-4.3rc2 中启用了导出索引数组(非关联)的功能。如上所述,此功能不太可能启用。
We can use this to create a function which restores any array data required:
我们可以使用它来创建一个函数来恢复所需的任何数组数据:
% function sharearray() {
array1=(a b c d)
}
% export -f sharearray
% bash -c 'sharearray; echo ${array1[*]}'
So, similar to the previous approach, invoke the child script with:
因此,与之前的方法类似,使用以下命令调用子脚本:
bash -c "sharearray; . otherscript.sh"
Or, you can conditionally invoke the sharearray
function in the child script by adding at some appropriate point:
或者,您可以sharearray
通过在某个适当的点添加来有条件地调用子脚本中的函数:
[ "`type -t sharearray`" = "function" ] && sharearray
Note there is no declare -a
in the sharearray
function, if you do that the array is implicitly localto the function, which is not what is wanted. bash-4.2 supports declare -g
that explicitly makes a variable global, so that (declare -ga
) could be used then. (Since associative arrays requiredeclare -A
you won't be able to use this method for associative arrays prior to bash-4.2.) The GNU parallel
documentation has useful variation on this method, see the discussion of --env
in the man page.
请注意declare -a
,sharearray
函数中没有,如果您这样做,数组对于函数来说是隐式本地的,这不是我们想要的。bash-4.2 支持declare -g
显式地将变量declare -ga
设为全局变量,这样就可以使用( ) 了。(由于关联数组需要declare -A
你将无法使用这种方法用于关联数组的bash-4.2前)的GNUparallel
文档对这种方法带来有益的变化,看到的讨论--env
在手册页。
Your question as phrased also indicates you may be having problems with export
itself. You can export a name after you've created or modified it. "exportable" is a flag or property of a variable, for convenience you can also set and export in a single statement. Up to bash-4.2 export
expects only a name, either a simple (scalar) variable or function name are supported.
您提出的问题也表明您可能遇到了问题export
。您可以在创建或修改名称后导出名称。“exportable”是变量的标志或属性,为方便起见,您还可以在单个语句中设置和导出。直到 bash-4.2export
只需要一个名称,支持简单(标量)变量或函数名称。
Even if you could (in future) export arrays, exporting selected indexes (a slice) may not be supported (though since arrays are sparse there's no reason it could not be allowed). Though bash also supports the syntax declare -a name[0]
, the subscript is ignored, and "name" is simply a normal indexed array.
即使您(将来)可以导出数组,也可能不支持导出选定的索引(切片)(尽管由于数组是稀疏的,因此没有理由不允许)。虽然 bash 也支持语法declare -a name[0]
,但下标被忽略,“name”只是一个普通的索引数组。
回答by Matt Whitlock
Jeez. I don't know why the other answers made this so complicated. Bash has nearly built-in support for this.
天啊。我不知道为什么其他答案让这变得如此复杂。Bash 几乎内置了对此的支持。
In the exporting script:
在导出脚本中:
myArray=( ' foo"bar ' $'\n''\nbaz)' ) # an array with two nasty elements
myArray="${myArray[@]@Q}" ./importing_script.sh
(Note, the double quotes are necessary for correct handling of whitespace within array elements.)
(注意,双引号对于正确处理数组元素中的空格是必要的。)
Upon entry to importing_script.sh
, the value of the myArray
environment variable comprises these exact 26 bytes:
进入 后importing_script.sh
,myArray
环境变量的值包含以下精确的 26 个字节:
' foo"bar ' $'\n\nbaz)'
Then the following will reconstitute the array:
然后以下内容将重组数组:
eval "myArray=( ${myArray} )"
CAUTION!Do not eval
like this if you cannot trust the source of the myArray
environment variable. This trick exhibits the "Little Bobby Tables"vulnerability. Imagine if someone were to set the value of myArray
to )?;?rm?-rf?/?#
.
警告!不要eval
这样,如果你不能信任的源myArray
环境变量。这个技巧展示了“Little Bobby Tables”漏洞。想象一下,如果有人将值设置为myArray
to )?;?rm?-rf?/?#
。
回答by Seppo Enarvi
The environmentis just a collection of key-value pairs, both of which are character strings. A proper solution that works for any kind of array could either
该环境只是一个键值对,这两者都是字符串的集合。适用于任何类型数组的适当解决方案可以
- Save each element in a different variable (e.g. MY_ARRAY_0=myArray[0]). Gets complicated because of the dynamic variable names.
- Save the array in the file system (declare -p myArray >file).
- Serialize all array elements into a single string.
- 将每个元素保存在不同的变量中(例如 MY_ARRAY_0=myArray[0])。由于动态变量名称而变得复杂。
- 将数组保存在文件系统中(声明 -p myArray >file)。
- 将所有数组元素序列化为单个字符串。
These are covered in the other posts. If you know that your values never contain a certain character (for example |
) and your keys are consecutive integers, you can simply save the array as a delimited list:
这些在其他帖子中都有介绍。如果您知道您的值从不包含某个字符(例如|
)并且您的键是连续整数,您可以简单地将数组保存为一个分隔列表:
export MY_ARRAY=$(IFS='|'; echo "${myArray[*]}")
And restore it in the child process:
并在子进程中恢复:
IFS='|'; myArray=($MY_ARRAY); unset IFS
回答by smoser
As lesmana reported, you cannot export arrays. So you have to serialize them before passing through the environment. This serialization useful other places too where only a string fits (su -c 'string', ssh host 'string'). The shortest code way to do this is to abuse 'getopt'
正如 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="" payload=""
eval set -- "$payload"
eval "unset $name && $name=("$@")"
}
Use it like this:
像这样使用它:
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
This does not address unset/sparse arrays. You might be able to reduce the 2 'eval' calls in restore_array.
这不解决未设置/稀疏数组。您也许可以减少 restore_array 中的 2 个“eval”调用。
回答by Sam Liddicott
Based on @mr.spuratic use of BASH_ENV
, here I tunnel $@
through script -f -c
基于@mr.spuratic 的使用BASH_ENV
,我在这里$@
通过script -f -c
script -c <command> <logfile>
can be used to run a command inside another pty (and process group) but it cannot pass any structured arguments to <command>
.
script -c <command> <logfile>
可用于在另一个 pty(和进程组)内运行命令,但它不能将任何结构化参数传递给<command>
.
Instead <command>
is a simple string to be an argument to the system
library call.
取而代之的<command>
是一个简单的字符串作为system
库调用的参数。
I need to tunnel $@
of the outer bash into $@
of the bash invoked by script.
我需要$@
将外部 bash隧道连接到$@
脚本调用的 bash 中。
As declare -p
cannot take @
, here I use the magic bash variable _
(with a dummy first array value as that will get overwritten by bash). This saves me trampling on any important variables:
由于declare -p
不能接受@
,这里我使用了魔法 bash 变量_
(带有一个虚拟的第一个数组值,因为它会被 bash 覆盖)。这让我免于践踏任何重要变量:
Proof of concept:
BASH_ENV=<( declare -a _=("" "$@") && declare -p _ ) bash -c 'set -- "${_[@]:1}" && echo "$@"'
概念证明:
BASH_ENV=<( declare -a _=("" "$@") && declare -p _ ) bash -c 'set -- "${_[@]:1}" && echo "$@"'
"But," you say, "you are passing arguments to bash -- and indeed I am, but these are a simple string of known character. Here is use by script
“但是,”你说,“你正在向 bash 传递参数——我确实是,但这些是一个简单的已知字符字符串。这里是 use by script
SHELL=/bin/bash BASH_ENV=<( declare -a _=("" "$@") && declare -p _ && echo 'set -- "${_[@]:1}"') script -f -c 'echo "$@"' /tmp/logfile
SHELL=/bin/bash BASH_ENV=<( declare -a _=("" "$@") && declare -p _ && echo 'set -- "${_[@]:1}"') script -f -c 'echo "$@"' /tmp/logfile
which gives me this wrapper function in_pty
:
这给了我这个包装函数in_pty
:
in_pty() {
SHELL=/bin/bash BASH_ENV=<( declare -a _=("" "$@") && declare -p _ && echo 'set -- "${_[@]:1}"') script -f -c 'echo "$@"' /tmp/logfile
}
in_pty() {
SHELL=/bin/bash BASH_ENV=<( declare -a _=("" "$@") && declare -p _ && echo 'set -- "${_[@]:1}"') script -f -c 'echo "$@"' /tmp/logfile
}
or this function-less wrapper as a composable string for Makefiles:
或者这个无函数包装器作为 Makefile 的可组合字符串:
in_pty=bash -c 'SHELL=/bin/bash BASH_ENV=<( declare -a _=("" "$$@") && declare -p _ && echo '"'"'set -- "$${_[@]:1}"'"'"') script -qfc '"'"'"$$@"'"'"' /tmp/logfile' --
in_pty=bash -c 'SHELL=/bin/bash BASH_ENV=<( declare -a _=("" "$$@") && declare -p _ && echo '"'"'set -- "$${_[@]:1}"'"'"') script -qfc '"'"'"$$@"'"'"' /tmp/logfile' --
...
...
$(in_pty) test --verbose $@ $^
$(in_pty) test --verbose $@ $^
回答by GreenFox
I was editing a different post and made a mistake. Augh. Anyway, perhaps this might help? https://stackoverflow.com/a/11944320/1594168
我正在编辑另一个帖子并犯了一个错误。啊。无论如何,也许这可能会有所帮助? https://stackoverflow.com/a/11944320/1594168
Note that because the shell's array format is undocumented on bash or any other shell's side, it is very difficult to return a shell array in platform independent way. You would have to check the version, and also craft a simple script that concatinates all shell arrays into a file that other processes can resolve into.
请注意,由于 shell 的数组格式在 bash 或任何其他 shell 方面没有记录,因此很难以独立于平台的方式返回 shell 数组。您必须检查版本,并制作一个简单的脚本,将所有 shell 数组连接到一个其他进程可以解析的文件中。
However, if you know the name of the array you want to take back homethen there is a way, while a bit dirty.
但是,如果您知道要带回家的阵列的名称,那么有一种方法,虽然有点脏。
Lets say I have
可以说我有
MyAry[42]="whatever-stuff";
MyAry[55]="foo";
MyAry[99]="bar";
So I want to take it home
所以我想把它带回家
name_of_child=MyAry
take_me_home="`declare -p ${name_of_child}`";
export take_me_home="${take_me_home/#declare -a ${name_of_child}=/}"
We can see it being exported, by checking from a sub-process
通过从子进程中检查,我们可以看到它被导出
echo ""|awk '{print "from awk =["ENVIRON["take_me_home"]"]"; }'
Result :
结果 :
from awk =['([42]="whatever-stuff" [55]="foo" [99]="bar")']
If we absolutely must, use the env var to dump it.
如果我们绝对必须,请使用 env var 转储它。
env > some_tmp_file
Then
然后
Before running the another script,
在运行另一个脚本之前,
# This is the magic that does it all
source some_tmp_file
回答by Aquarius Power
you (hi!) can use this, dont need writing a file, for ubuntu 12.04, bash 4.2.24
你(嗨!)可以使用这个,不需要写文件,对于 ubuntu 12.04,bash 4.2.24
Also, your multiple lines array can be exported.
此外,您的多行数组可以导出。
cat >>exportArray.sh
猫 >>exportArray.sh
function FUNCarrayRestore() {
local l_arrayName=
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=
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
test this example on terminal bash (works with bash 4.2.24):
在终端 bash 上测试此示例(适用于 bash 4.2.24):
source exportArray.sh
list=(a b c)
FUNCarrayFakeExport list
bash
echo ${list[@]} #empty :(
FUNCarrayRestore list
echo ${list[@]} #profit! :D
I may improve it here
我可以在这里改进它
PS.: if someone clears/improve/makeItRunFaster I would like to know/see, thx! :D
PS。:如果有人清除/改进/makeItRunFaster我想知道/看到,谢谢!:D
回答by markantonio37
For arrays with values without spaces, I've been using a simple set of functions to iterate through each array element and concatenate the array:
对于没有空格的值的数组,我一直在使用一组简单的函数来遍历每个数组元素并连接数组:
_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=
array=${str//\"/}
array=(${array//[()]/""})
export array=${array[@]}
}
The first function with turn the array into a string by adding the opening and closing parentheses and escaping all of the double quotation marks. The second function will strip the quotation marks and the parentheses and place them into a dummy array.
第一个函数通过添加左括号和右括号并转义所有双引号将数组转换为字符串。第二个函数将去除引号和括号并将它们放入一个虚拟数组中。
In order export the array, you would pass in all the elements of the original array:
为了导出数组,您需要传入原始数组的所有元素:
array=(foo bar)
_arrayToStr ${array[@]}
At this point, the array has been exported into the value $arrayString. To import the array in the destination file, rename the array and do the opposite conversion:
至此,数组已经导出为值$arrayString。要在目标文件中导入数组,请重命名数组并进行相反的转换:
_strToArray "$arrayName"
newArray=(${array[@]})
回答by Sam Liddicott
Muchthanks to @stéphane-chazelas who pointed out all the problems with my previous attempts, this now seems to work to serialise an array to stdout or into a variable.
非常感谢@stéphane-chazelas,他指出了我之前尝试的所有问题,现在这似乎可以将数组序列化为标准输出或变量。
This technique does not shell-parse the input (unlike declare -a
/declare -p
) and so is safe against malicious insertion of metacharacters in the serialised text.
此技术不会对输入进行 shell 解析(与declare -a
/不同declare -p
),因此可以安全地防止在序列化文本中恶意插入元字符。
Note: newlines are not escaped, because read
deletes the \<newlines>
character pair, so -d ...
must instead be passed to read, and then unescaped newlines are preserved.
注意:换行符没有转义,因为read
删除了\<newlines>
字符对,所以-d ...
必须改为传递给read,然后保留未转义的换行符。
All this is managed in the unserialise
function.
所有这些都在unserialise
函数中进行管理。
Two magic characters are used, the field separator and the record separator (so that multiple arrays can be serialized to the same stream).
使用了两个魔法字符,字段分隔符和记录分隔符(以便多个数组可以序列化到同一个流)。
These characters can be defined as FS
and RS
but neither can be defined as newline
character because an escaped newline is deleted by read
.
这些字符可以定义为FS
和RS
但都不能定义为newline
字符,因为转义的换行符被删除read
。
The escape character must be \
the backslash, as that is what is used by read
to avoid the character being recognized as an IFS
character.
转义字符必须是\
反斜杠,因为这是用来read
避免字符被识别为IFS
字符的。
serialise
will serialise "$@"
to stdout, serialise_to
will serialise to the varable named in $1
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="" serialise "${@:2}"
}
unserialise() {
local IFS="${FS:-;}"
if test -n ""
then read -d "${RS:-:}" -a "" <<<"${*:2}"
else read -d "${RS:-:}" -a ""
fi
}
and unserialise with:
并反序列化:
unserialise data # read from stdin
or
或者
unserialise data "$serialised_data" # from args
e.g.
例如
$ 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:
(without a trailing newline)
(没有尾随换行符)
read it back:
再读一遍:
$ 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
or
或者
unserialise array # read from stdin
Bash's read
respects the escape character \
(unless you pass the -r flag) to remove special meaning of characters such as for input field separation or line delimiting.
Bashread
尊重转义字符\
(除非您传递 -r 标志)以删除字符的特殊含义,例如用于输入字段分隔或行分隔。
If you want to serialise an array instead of a mere argument list then just pass your array as the argument list:
如果你想序列化一个数组而不是单纯的参数列表,那么只需将你的数组作为参数列表传递:
serialise_array "${my_array[@]}"
You can use unserialise
in a loop like you would read
because it is just a wrapped read - but remember that the stream is not newline separated:
您可以unserialise
像在循环中一样使用,read
因为它只是一个包装读取 - 但请记住,流不是换行符分隔的:
while unserialise array
do ...
done