在shell别名中设置环境变量

12

在我的系统上,我安装了两个版本的Java - 有些程序需要Java 7,有些需要Java 8。

Java 8是我的系统默认版本,所以当我运行Java 7命令时,我使用的是:

JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.*.jdk/Contents/Home/ \
java_7_program

我想设置一个别名以便我可以代替写

j7 java_7_program

我已经定义:

alias j7='JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.*.jdk/Contents/Home/'

但是运行j7 java -version会产生以下结果:

java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
man页面(搜索“别名”)指出这是直接替换。那么为什么这不起作用呢? bash --version会打印GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin14.5.0) 以下是一个更简单的例子(没有Java):
$ alias foo='BAR=baz'
$ type foo
foo is aliased to `BAR=baz'
$ foo echo $BAR
[blank line]

尝试运行 foo env 命令,你会发现 BAR 的值被设置为 baz。同时,运行 foo /bin/echo $BAR 命令也应该可以正常工作。区别在于 echo 是一个 shell 内置命令,所以显式地运行二进制文件才能得到正确的结果。 - Richard
关于您的编辑:正如我之前所说,当您键入foo echo $BAR时,BAR并没有在当前shell中设置,而是在echo的环境中设置;并且$BARecho运行之前被展开。尝试以下任何一种方法,您会发现它可以工作:1. 在单独的一行上键入foo,然后在其后键入echo $BAR或等效地键入foo; echo "$BAR";2. foo eval 'echo "$BAR"';3.(某种程度上类似)foo bash -c 'echo "$BAR"' - gniourf_gniourf
好的,这里有几个问题。一个是我问的问题(为什么别名没有设置变量?),而混淆因素是运行java时使用的是/bin/java,它无论JAVA_HOME变量如何设置都会使用1.8版本。 - Fabian Tamp
1
重新阅读所有内容,似乎你的问题只是来自于引号'的使用!只需删除引号:alias j7=JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.*.jdk/Contents/Home/就可以正常工作了! - F. Hauri - Give Up GitHub
@F.Hauri 对我不起作用。但如果你已经执行了多次(即 j7 ; j7 echo $JAVA_HOME),那么它会起作用。 - Fabian Tamp
@F.Hauri,你的回答怎么了?虽然它没有直接回答问题,但有关函数的一些内容仍然很有用。 - Fabian Tamp
4个回答

9
回答您的具体问题:
当您像这样执行操作时:
bar=foo my_command

然后bar被设置在my_command的环境中(并且当前shell看不到它)。因此,当您执行以下操作时:

bar=stuff
bar=foo my_command "$bar"

自从扩展$bar发生在执行my_command之前,那么就相当于执行以下操作:
bar=foo my_command stuff

自变量 $bar执行命令之前就已经被展开,这解释了你在例子中看到的[空白行]
$ alias foo='BAR=baz'
$ type foo
foo is aliased to `BAR=baz'
$ foo echo $BAR
[blank line]

只是为了好玩,试试这些:

$ alias foo=BAR=baz
$ BAR=something
$ foo echo "$BAR"
something

makes sense?

$ alias foo=BAR=baz
$ foo eval 'echo "$BAR"'
baz

这是因为BAReval的环境中被传递,然后echo "$BAR"按照预期值(请注意引号!)进行扩展…。

同样地,

$ alias foo=BAR=baz
$ foo sh -c 'echo "$BAR"'
baz

1
值得注意的是,alias foo='BAR=baz ;' 也可以起作用。谢谢。 - Fabian Tamp
但是你不是说过***eval是邪恶的吗!***? - F. Hauri - Give Up GitHub
@F.Hauri:我没有 :)...在这种情况下,它并不是真正的邪恶(就像上一个例子中的 sh 一样邪恶/好)。 - gniourf_gniourf

1

在设置环境之前无法使用Shell别名执行任何操作。

Shell别名只能保存普通命令,没有通配符或子命令。

如果要执行此类操作,您需要编写一个“包装器”脚本或至少一个函数。

sudo cat >/usr/local/bin/j7 <<<eof
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.*.jdk/Contents/Home/
java $@
eof
sudo chmod +x /usr/local/bin/j7

或者将此函数定义添加到您的.bashrc文件中:
j7() {
  export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.*.jdk/Contents/Home/
  java $@
}

真正有用的Bash包装器

类似于:

j7 () {
    local JLIBROOT dir
    # JLIBROOT=/usr/lib/jdk
    JLIBROOT=/Library/Java/JavaVirtualMachines
    while read dir && [ "$dir" = "${dir//1.7.}" ] ;do
        :
      done < <(
          /bin/ls -1trd $JLIBROOT/*
    )
    if [ "$dir" != "${dir//1.7.}" ] ;then
          export JAVA_HOME=$dir/Contents/Home
          java $@
      else
          echo "Version 1.7 not found in '$JLIBROOT'."
      fi
}

可以在我的Linux桌面上工作...


1
为什么你说一个 shell 别名不能用来修改环境?因为它可以... alias abc='PATH=somewhere' 然后 abc 然后 declare -p PATH... 在 POSIX shells 中也可以工作(但显然不能使用 declare 来查看变量)。 - gniourf_gniourf

1

jdk1.7.*.jdk 位可能是问题所在。如果我明确指定版本,它就可以正常工作。

您可以使用 /usr/libexec/java_home -v 1.7 获取最新的 1.7 版本安装。

因此,重新设置您的别名,请尝试:

alias j7='JAVA_HOME=`/usr/libexec/java_home -v 1.7`'

注意反引号包围的java_home部分,这将执行命令以生成正确的路径来设置JAVA_HOME

它对我不起作用。作为一个简化的例子:alias foo='BAR=baz' ; foo echo $BAR 打印出一行空白。 - Fabian Tamp
@FabianTamp alias foo='BAR=baz'fooecho "$BAR"分别在三行中(好吧,只有别名声明需要在单独的一行中)。 - gniourf_gniourf
@FabianTamp 我怀疑它不起作用。你的 shell 是什么?你真的将这三个命令分别输入了吗? - gniourf_gniourf
是的。这里也复制粘贴了输出,但由于换行符被剥离而变得混乱。 $ alias foo ='BAR = baz' $ type foo foo被别名为'BAR = baz' $ foo echo $ BAR [空行] - Fabian Tamp
Fabian,我认为这是因为echo在另一个shell中,通常shell变量不会被传递。如果你尝试我的别名并执行j7 java -version - 这在我的Mac上运行10.10.5,并且bash版本为3.2.57时可以工作。 - Richard
显示剩余2条评论

1

使用 env

您可以使用 env 工具来设置环境变量。

alias foo='env - X=42 perl -E"say \$ENV{X}"'

这将设置一个别名 foo,声明环境变量 X 并将其初始化为 42,然后执行 perl 并指示它打印环境变量 X


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接