Bash 数组导出?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15825353/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 05:06:42  来源:igfitidea点击:

Bash array export?

bash

提问by Robottinosino

Is it possible to declare and export a basharray from a single statement within a function?

是否可以从函数内的单个语句声明和导出bash数组?

My current workaround is to first declare, then to export.

我目前的解决方法是先声明,然后导出。

f() { foo=(1 2 3); export foo; }; f; export -p | grep foo=
declare -ax foo='([0]="1" [1]="2" [2]="3")'

I observe that:

我观察到:

f() { export bar=(1 2 3); }; f; export -p | grep bar=
<no output>

and:

和:

f() { export baz="(1 2 3)"; }; f; export -p | grep baz=
declare -x baz="(1 2 3)" # not an array

I use bashv3.2.48(1)-release and can't upgrade.

我使用bashv3.2.48(1)-release 并且无法升级。



Some background:

一些背景:

I have a friend with whome I am trying to study "some" Django.

我有一个朋友,我想和他一起学习“一些”Django。

He's more clueless than me at the command line and needs the following, on OSX hackintosh:

他在命令行上比我更无能,在 OSX hackintosh 上需要以下内容:

  • launch an interactive shell
  • find the PATH variable including the django bin dir, as per my specification
  • find an updated PYTHONPATH env var, with the various django libs visible
  • a nice interactive ipython shell to start typing commands in after double-clicking
  • (tricky) an interactive shell to fall back to once he CTRL-D exits from ipython
  • 启动一个交互式 shell
  • 根据我的规范,找到包括 django bin 目录的 PATH 变量
  • 找到更新的 PYTHONPATH env var,可以看到各种 django 库
  • 一个很好的交互式 ipython shell,可以在双击后开始输入命令
  • (棘手)一旦他 CTRL-D 从 ipython 退出,就可以回退到一个交互式 shell

On Windows, I would alias a command shortcut, like cmd.exe, set custom environment variables and start ipython. This works: after exiting ipython one still finds oneself in a command interpreter.

在 Windows 上,我会给命令快捷方式取别名,比如 cmd.exe,设置自定义环境变量并启动 ipython。这是有效的:退出 ipython 后,仍然会发现自己处于命令解释器中。

Is this possible at all with OSX's standard bash? I played with bash -c but many things don't work, like changing into a directory, being able to exit python and stayin a terminal, etc. Also played with -s.

使用 OSX 的标准 bash 是否可以做到这一点?我玩过 bash -c 但很多东西都不起作用,比如切换到目录,能够退出 python 并在终端等。也用 -s 玩。

采纳答案by ormaaj

You can't export an array in Bash (or any other shell). Bash will neverexport an array to the environment (until maybe implemented someday, see the bugssection in the manpage).

您不能在 Bash(或任何其他 shell)中导出数组。Bash永远不会将数组导出到环境中(直到有一天可能实现,请参阅bugs联机帮助页中的部分)。

There are a couple things going on here. Again, setting the -xattribute on an array is nonsensical because it won't actually be exported. The onlyreason you're seeing those results is because you defined the array before localizing it, causing it to drop down to the next-outermost scope in which that name has been made local (or the global scope).

这里有几件事情正在发生。同样,-x在数组上设置属性是无意义的,因为它实际上不会被导出。您看到这些结果的唯一原因是因为您在本地化之前定义了数组,导致它下降到下一个最外面的范围,其中该名称已成为本地(或全局范围)。

So to be clear, whenever you use a declaration command, you're always creating a local except when you use exportor readonlywith a non-array assignment as an argument, because these are POSIX, which doesn't specify either locals or arrays.

所以要明确的是,每当您使用声明命令时,您总是在创建一个局部变量,除非您使用exportreadonly将非数组赋值作为参数,因为这些是 POSIX,它不指定局部变量或数组。

function f {
    typeset -a a # "a" is now local to "f"
    g
    printf 'Now back in "f": %s\n' "$(typeset -p a)"
}

function g {
    a=(1 2 3)                               # Assigning f's localized "a"
    typeset -a a                            # A new local a
    printf 'In "g": %s\n' "$(typeset -p a)" # g's local is now empty.
    a=(a b c)                               # Now set g's local to a new value.
    printf 'Still in "g": %s\n' "$(typeset -p a)"
}

f

# In "g": declare -a a='()'
# Still in "g": declare -a a='([0]="a" [1]="b" [2]="c")'
# Now back in "f": declare -a a='([0]="1" [1]="2" [2]="3")'

It seems if you give an array as an argument to exportthen Bash will make it local like any other declaration command. Basically don't use exportto define an array. exportis a POSIX builtin and its behavior is undefined for arrays, which is probably why bash just treats it as though you had used typeset -ax a=(1 2 3). Use typeset, local, or declare. There's really no way to know what's "correct", or even compare with other shells. ksh93 is the only other that accepts array assignments as arguments to declaration commands, and its behavior doesn't agree with Bash.

似乎如果你给一个数组作为参数,export那么 Bash 会像任何其他声明命令一样使它成为本地的。基本上不用export来定义数组。export是一个 POSIX 内置函数,它的行为对于数组是未定义的,这可能就是为什么 bash 只是把它当作你已经使用typeset -ax a=(1 2 3). 使用typesetlocal、 或declare。真的没有办法知道什么是“正确的”,甚至无法与其他 shell 进行比较。ksh93 是唯一接受数组赋值作为声明命令参数的另一个,它的行为与 Bash 不一致。

The important thing to understand is that the environment has nothing to do with it, you're just playing with the quirks of locals when trying to do nonstandard things with POSIX-only commands.

需要了解的重要一点是,环境与它无关,当您尝试使用仅限 POSIX 的命令执行非标准操作时,您只是在玩弄当地人的怪癖。

In order to actually get the effect you want, you may use typeset -p.

为了实际获得您想要的效果,您可以使用typeset -p.

function f {
    typeset -a "=(1 2 3)"
    typeset -p ""
}

typeset -a arr
eval "$(f arr)"
typeset -p arr

Bash guarantees you'll get out the correct result, but I find this isn't very useful and rarely use this approach. It's usually better to just let the caller define a local and use dynamic scope do the work (as you've already discovered... just do it without exporting).

Bash 保证你会得到正确的结果,但我发现这不是很有用,很少使用这种方法。通常最好让调用者定义一个本地并使用动态范围来完成工作(正如您已经发现的那样......只需在不导出的情况下进行)。

In Bash 4.3 you can use typeset -n, which is really the most correct way to handle this.

在 Bash 4.3 中,您可以使用typeset -n,这确实是处理此问题的最正确方法。

回答by Jonathan Leffler

The first option seems to be the only one that's going to work. I experimented with bash4.2 as well as 3.2.48. The interesting information, to me, were these minor variants of your examples:

第一个选项似乎是唯一可行的选项。我试验了bash4.2 和 3.2.48。对我来说,有趣的信息是您示例的这些小变种:

$ f() { declare -a bar=(1 2 3); export bar; export -p | grep bar=; }; f; export -p | grep bar=
declare -ax bar='([0]="1" [1]="2" [2]="3")'
$ f() { export  bar=(1 2 3); export -p | grep bar=; }; f; export -p | grep bar=
declare -ax bar='([0]="1" [1]="2" [2]="3")'
$ f() { bar=(1 2 3); export bar; export -p | grep bar=; }; f; export -p | grep bar=
declare -ax bar='([0]="1" [1]="2" [2]="3")'
declare -ax bar='([0]="1" [1]="2" [2]="3")'
$ unset bar
$ f() { bar=(1 2 3); }; f; set | grep bar=
bar=([0]="1" [1]="2" [2]="3")
    bar=(1 2 3)
$

In these examples, I test the exportinside the function as well as outside the function. Because the variables are being defined in the function, they appear to be scope-limited to the function. The exception is when the variable is defined before any attributes are applied — the last two functions. There a global variable is created, and then exported (in one case).

在这些示例中,我测试了export函数内部以及函数外部。因为变量是在函数中定义的,所以它们的作用域似乎仅限于函数。例外情况是在应用任何属性之前定义变量 - 最后两个函数。创建一个全局变量,然后导出(在一种情况下)。

So, if you're going to get the array exported from the function, you have to create it without the declareor exportstatements (because those make the variable local to the function), and then export it.

因此,如果您要从函数中导出数组,则必须在没有declareorexport语句的情况下创建它(因为这些语句使变量成为函数的局部变量),然后将其导出。

I hope that explains it; I can see fuzzily what's going on and it makes sense, after a fashion. I'm not sure I explained it as well as it should be explained.

我希望能解释它;我可以模糊地看到正在发生的事情,这是有道理的,在时尚之后。我不确定我是否解释了它以及它应该被解释的情况。



In the declaresection of the bashmanual, it says:

在手册的declare部分bash,它说:

When used in a function, declaremakes each name local, as with the localcommand.

在函数中使用时,declare使每个名称都是本地的,就像local命令一样。

There isn't equivalent wording in the export. However, the observed behaviour is as ifexportis implemented by declare -x.

中没有等效的措辞export。但是,观察到的行为好像export是由 实现的declare -x

回答by Wiimm

If I want to export the array MY_ARRAY, I use:

如果我想导出数组 MY_ARRAY,我使用:

[[ $MY_ARRAY ]] && export A_MY_ARRAY=$(declare -p MY_ARRAY)

at caller side and

在呼叫方和

[[ $A_MY_ARRAY =~ ^declare ]] && eval $A_MY_ARRAY

at sub script.

在子脚本。