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?
出于几个原因,我需要将数组初始化为多行。你有什么办法吗?
9 个解决方案
#1
37
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维护者)的声明可能是关于这个“bug”的最正式的文档:
There isn't really a good way to encode an array variable into the environment.
将数组变量编码到环境中并不是一种好方法。
http://www.mail-archive.com/bug-bash@gnu.org/msg01774.html
http://www.mail-archive.com/bug-bash@gnu.org/msg01774.html
#2
23
TL;DR: exportable arrays are not directly supported up to and including bash-4.3, but you can (effectively) export arrays in one of two ways:
导出数组不直接支持和包括bash-4.3,但是您可以(有效地)以以下两种方式之一导出数组:
- a simple modification to the way the child scripts are invoked
- 对子脚本调用方式的简单修改
- use an exported function to 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 not enabled in 4.3. If you define ARRAY_EXPORT
when building, the build will fail. The author has stated it is not planned to complete this feature.
或者,您可以等到发布bash-4.3(到2014年2月处于开发/RC状态,请参阅Changelog中的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 environment is 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=值对的集合,可以通过各种方式从一个进程传递给它的子进程(实际上是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)和env或printenv的输出不同。
When you invoke another 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环境仅仅是名称=值对,没有额外的含义,所以没有一致的方式对类型化变量进行编码或格式化,请参阅下面关于函数的有趣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 complexity some 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环境输出为一个或多个可以用于重构“名称”类型和值的声明语句的集合。这是基本的串行化,但不太复杂,其他一些答案暗示了这一点。声明-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.
在crontabs中,有时会使用上面的bash -c“…”形式的变体来设置变量。
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 substitution to 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文件,并使用返回的大小来读取文件;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作为bash在历史/POSIX模式下不会授予BASH_ENV荣誉。
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 ${!展开它们的列表,而不是枚举它们。
You probably should not attempt to export and re-import the entire bash 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来启用这种行为,将导致(process)环境中出现这种情况,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源文件变量。c您将看到以(){开头的变量是特别处理的。(尽管禁止使用此语法创建带有声明-f的函数)。更新:“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)
is enabled.
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 local to 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 require declare -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.
注意sharearray函数中没有声明-a,如果这样做,数组就会隐式地局部于函数,这不是我们想要的。bash-4.2支持声明-g显式地创建一个变量全局变量,这样就可以使用(声明-ga)。(因为关联数组需要声明-A,所以在bash-4.2之前,您无法将此方法用于关联数组。)GNU并行文档在这个方法上有一些有用的变体,请参阅“手册页”中的“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.
你提出的问题也表明你可能在出口本身上有问题。您可以在创建或修改名称之后导出名称。“exportable”是一个变量的标志或属性,为了方便,您还可以在单个语句中设置和导出。到bash-4.2为止,export只需要一个名称,支持简单(标量)变量或函数名。
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还支持语法声明-a名称[0],但是会忽略下标,而“name”只是一个普通的索引数组。
#3
1
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主机'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=("\$@")"
}
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”调用。
#4
1
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 / #
.
谨慎!如果不能信任myArray环境变量的源,不要像这样计算。这个技巧展示了“小博比表”的漏洞。假设有人将myArray的值设置为);rm -rf / #。
#5
0
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=$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
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
如果有人清理/改进/使它运行得更快,我想知道/看到,谢谢!:D
#6
0
I was editing a different post and made a mistake. Augh. Anyway, perhaps this might help? https://*.com/a/11944320/1594168
我在编辑另一篇文章时犯了一个错误。Augh。不管怎样,这可能会有帮助吗?https://*.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 home then 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
#7
0
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=$1
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[@]})
#8
0
Much thanks 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.
多亏了@stephane-chazelas,他指出了我之前尝试的所有问题,现在看来这可以将数组序列化为stdout或序列化为变量。
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解析(与声明-a/声明-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删除了\
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,但不能将它们定义为换行字符,因为转义的换行被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
序列化将“$@”序列化为stdout, 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
}
and unserialise with:
和unserialise:
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.
Bash的read尊重转义字符\(除非您通过-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,就像你会读的那样,因为它只是一个被包装的阅读——但是记住,流不是换行的新行:
while unserialise array
do ...
done
#9
0
Based on @mr.spuratic use of BASH_ENV
, here I tunnel $@
through script -f -c
基于@mr。BASH_ENV的快速使用,这里我通过脚本-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>
.
脚本-c
Instead <command>
is a simple string to be an argument to the system
library call.
相反,
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:
因为声明-p不能接受@,所以在这里我使用了magic bash变量_(使用虚拟的第一个数组值,因为它将被bash重写)。这避免了我对任何重要变量的践踏:
Proof of concept: BASH_ENV=<( declare -a _=("" "$@") && declare -p _ ) bash -c 'set -- "${_[@]:1}" && echo "$@"'
那么它将扩展BASH_ENV = <概念证明:(声明——_ =(““$ @”)& &声明- p _)bash - c组——“$ { _[@]:1 } " & &回声“$ @”<>
"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——实际上我是,但是这些是一个简单的已知字符字符串。这里是脚本使用
SHELL=/bin/bash BASH_ENV=<( declare -a _=("" "$@") && declare -p _ && echo 'set -- "${_[@]:1}"') script -f -c 'echo "$@"' /tmp/logfile
壳那么它将扩展BASH_ENV = < = / bin / bash(声明——_ =(““$ @”)& &声明- p _ & &回声“设置——“$ { 1 } _[@]:" ')脚本- f - c”呼应“$ @”“/ tmp /日志文件
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(){壳那么它将扩展BASH_ENV = < = / bin / bash(声明——_ =(““$ @”)& &声明- p _ & &回声“设置——“$ { 1 } _[@]:" ')脚本- f - c”呼应“$ @”“/ tmp /日志文件}
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 '壳那么它将扩展BASH_ENV = < = / bin / bash(声明——_ =(" " " $ $ @ ")& &声明- p _ & &回声“”“”“设置——“$ $ { 1 } _[@]:“”“”“”)脚本的优惠卡”“”“”“$ $ @”“”“”“/ tmp /日志文件”—
...
…
$(in_pty) test --verbose $@ $^
美元(in_pty)测试——详细$ @ $ ^
#1
37
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维护者)的声明可能是关于这个“bug”的最正式的文档:
There isn't really a good way to encode an array variable into the environment.
将数组变量编码到环境中并不是一种好方法。
http://www.mail-archive.com/bug-bash@gnu.org/msg01774.html
http://www.mail-archive.com/bug-bash@gnu.org/msg01774.html
#2
23
TL;DR: exportable arrays are not directly supported up to and including bash-4.3, but you can (effectively) export arrays in one of two ways:
导出数组不直接支持和包括bash-4.3,但是您可以(有效地)以以下两种方式之一导出数组:
- a simple modification to the way the child scripts are invoked
- 对子脚本调用方式的简单修改
- use an exported function to 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 not enabled in 4.3. If you define ARRAY_EXPORT
when building, the build will fail. The author has stated it is not planned to complete this feature.
或者,您可以等到发布bash-4.3(到2014年2月处于开发/RC状态,请参阅Changelog中的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 environment is 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=值对的集合,可以通过各种方式从一个进程传递给它的子进程(实际上是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)和env或printenv的输出不同。
When you invoke another 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环境仅仅是名称=值对,没有额外的含义,所以没有一致的方式对类型化变量进行编码或格式化,请参阅下面关于函数的有趣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 complexity some 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环境输出为一个或多个可以用于重构“名称”类型和值的声明语句的集合。这是基本的串行化,但不太复杂,其他一些答案暗示了这一点。声明-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.
在crontabs中,有时会使用上面的bash -c“…”形式的变体来设置变量。
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 substitution to 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文件,并使用返回的大小来读取文件;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作为bash在历史/POSIX模式下不会授予BASH_ENV荣誉。
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 ${!展开它们的列表,而不是枚举它们。
You probably should not attempt to export and re-import the entire bash 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来启用这种行为,将导致(process)环境中出现这种情况,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源文件变量。c您将看到以(){开头的变量是特别处理的。(尽管禁止使用此语法创建带有声明-f的函数)。更新:“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)
is enabled.
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 local to 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 require declare -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.
注意sharearray函数中没有声明-a,如果这样做,数组就会隐式地局部于函数,这不是我们想要的。bash-4.2支持声明-g显式地创建一个变量全局变量,这样就可以使用(声明-ga)。(因为关联数组需要声明-A,所以在bash-4.2之前,您无法将此方法用于关联数组。)GNU并行文档在这个方法上有一些有用的变体,请参阅“手册页”中的“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.
你提出的问题也表明你可能在出口本身上有问题。您可以在创建或修改名称之后导出名称。“exportable”是一个变量的标志或属性,为了方便,您还可以在单个语句中设置和导出。到bash-4.2为止,export只需要一个名称,支持简单(标量)变量或函数名。
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还支持语法声明-a名称[0],但是会忽略下标,而“name”只是一个普通的索引数组。
#3
1
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主机'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=("\$@")"
}
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”调用。
#4
1
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 / #
.
谨慎!如果不能信任myArray环境变量的源,不要像这样计算。这个技巧展示了“小博比表”的漏洞。假设有人将myArray的值设置为);rm -rf / #。
#5
0
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=$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
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
如果有人清理/改进/使它运行得更快,我想知道/看到,谢谢!:D
#6
0
I was editing a different post and made a mistake. Augh. Anyway, perhaps this might help? https://*.com/a/11944320/1594168
我在编辑另一篇文章时犯了一个错误。Augh。不管怎样,这可能会有帮助吗?https://*.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 home then 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
#7
0
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=$1
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[@]})
#8
0
Much thanks 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.
多亏了@stephane-chazelas,他指出了我之前尝试的所有问题,现在看来这可以将数组序列化为stdout或序列化为变量。
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解析(与声明-a/声明-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删除了\
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,但不能将它们定义为换行字符,因为转义的换行被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
序列化将“$@”序列化为stdout, 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
}
and unserialise with:
和unserialise:
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.
Bash的read尊重转义字符\(除非您通过-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,就像你会读的那样,因为它只是一个被包装的阅读——但是记住,流不是换行的新行:
while unserialise array
do ...
done
#9
0
Based on @mr.spuratic use of BASH_ENV
, here I tunnel $@
through script -f -c
基于@mr。BASH_ENV的快速使用,这里我通过脚本-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>
.
脚本-c
Instead <command>
is a simple string to be an argument to the system
library call.
相反,
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:
因为声明-p不能接受@,所以在这里我使用了magic bash变量_(使用虚拟的第一个数组值,因为它将被bash重写)。这避免了我对任何重要变量的践踏:
Proof of concept: BASH_ENV=<( declare -a _=("" "$@") && declare -p _ ) bash -c 'set -- "${_[@]:1}" && echo "$@"'
那么它将扩展BASH_ENV = <概念证明:(声明——_ =(““$ @”)& &声明- p _)bash - c组——“$ { _[@]:1 } " & &回声“$ @”<>
"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——实际上我是,但是这些是一个简单的已知字符字符串。这里是脚本使用
SHELL=/bin/bash BASH_ENV=<( declare -a _=("" "$@") && declare -p _ && echo 'set -- "${_[@]:1}"') script -f -c 'echo "$@"' /tmp/logfile
壳那么它将扩展BASH_ENV = < = / bin / bash(声明——_ =(““$ @”)& &声明- p _ & &回声“设置——“$ { 1 } _[@]:" ')脚本- f - c”呼应“$ @”“/ tmp /日志文件
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(){壳那么它将扩展BASH_ENV = < = / bin / bash(声明——_ =(““$ @”)& &声明- p _ & &回声“设置——“$ { 1 } _[@]:" ')脚本- f - c”呼应“$ @”“/ tmp /日志文件}
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 '壳那么它将扩展BASH_ENV = < = / bin / bash(声明——_ =(" " " $ $ @ ")& &声明- p _ & &回声“”“”“设置——“$ $ { 1 } _[@]:“”“”“”)脚本的优惠卡”“”“”“$ $ @”“”“”“/ tmp /日志文件”—
...
…
$(in_pty) test --verbose $@ $^
美元(in_pty)测试——详细$ @ $ ^