【问题标题】:Java: System.getProperty("user.home") returns "?"Java:System.getProperty("user.home") 返回“?”
【发布时间】:2021-11-05 20:58:23
【问题描述】:

我完全迷失了这个:System.getProperty("user.home")System.getProperty("user.name") 返回一个问号“?”。

System-Specs:
Kubuntu 9.04
Gnome 2.2.61
Java 1.5.0_16

我的测试用例是这样的:

$ more Test.java
class Test { public static void main( String[] args ) { System.out.println( System.getProperties() ); } }

结果是(为更好的可读性添加了换行符,替换了公司名称和自己的名称):

$ javac Test.java
$ java Test
{
java.runtime.name=Java(TM) 2 Runtime Environment, Standard Edition,
sun.boot.library.path=/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/i386,
java.vm.version=1.5.0_16-b02,
java.vm.vendor=Sun Microsystems Inc.,
java.vendor.url=http://java.sun.com/,
path.separator=:,
java.vm.name=Java HotSpot(TM) Server VM,
file.encoding.pkg=sun.io,
sun.java.launcher=SUN_STANDARD,
user.country=US,
sun.os.patch.level=unknown,
java.vm.specification.name=Java Virtual Machine Specification,
user.dir=/home/MYCOMPANY/myname/temp,
java.runtime.version=1.5.0_16-b02,
java.awt.graphicsenv=sun.awt.X11GraphicsEnvironment,
java.endorsed.dirs=/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/endorsed,
os.arch=i386,
java.io.tmpdir=/tmp,
line.separator=
,
java.vm.specification.vendor=Sun Microsystems Inc.,
os.name=Linux,
sun.jnu.encoding=UTF-8,
java.library.path=/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/i386/server:/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/i386:/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/../lib/i386,
java.specification.name=Java Platform API Specification,
java.class.version=49.0,
sun.management.compiler=HotSpot Server Compiler,
os.version=2.6.28-15-generic,
user.home=?,
user.timezone=,
java.awt.printerjob=sun.print.PSPrinterJob,
file.encoding=UTF-8,
java.specification.version=1.5,
java.class.path=.,
user.name=?,
java.vm.specification.version=1.0,
java.home=/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre,
sun.arch.data.model=32,
user.language=en,
java.specification.vendor=Sun Microsystems Inc.,
java.vm.info=mixed mode,
java.version=1.5.0_16,
java.ext.dirs=/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/ext,
sun.boot.class.path=/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/rt.jar:/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/i18n.jar:/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/sunrsasign.jar:/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/jsse.jar:/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/jce.jar:/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/lib/charsets.jar:/home/MYCOMPANY/myname/apps/jdk1.5.0_16/jre/classes,
java.vendor=Sun Microsystems Inc.,
file.separator=/,
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi,
sun.io.unicode.encoding=UnicodeLittle,
sun.cpu.endian=little,
sun.desktop=gnome,
sun.cpu.isalist=
}

有人经历过吗? Java 在哪里寻找用户和主目录?我已经检查了设置正确的HOME环境变量。

【问题讨论】:

  • 嗯。从来没见过。 echo $HOME 可以从命令行工作吗?尝试打印出System.getProperties()
  • 可能来自 /etc/passwd?主目录是动态的吗?
  • 你确定这是 sun 实现吗?

标签: java kubuntu


【解决方案1】:

这有点尴尬,但解决方案就是在 64 位系统上使用 64 位 JDK。我从旧机器上复制了所有内容,这也意味着 32 位 JDK,这就是问题所在。它在 64 位运行时按预期工作。

抱歉打扰了。

【讨论】:

  • 不要为打扰而感到抱歉。这是 jvm 中的一个真正的错误,这篇文章也帮助了这里的其他人。
  • 这是bugs.sun.com/bugdatabase/view_bug.do?bug_id=6972329(未确认为JDK错误,可能是系统问题)。
  • 我们长期遇到同样的问题。在阅读了@PascalThivent 引用的错误报告后,这正是我们的情况。此问题不会发生在本地帐户上,但只会发生在 LDAP 帐户上。问题是我们的系统中没有安装 32 位版本的 libnss_ldap。在我们安装了 32 位 nss_pam_ldap 包之后,一切都很顺利。
  • 这是迄今为止解决 LDAP 用户主目录问题的最佳解决方案。
  • 你不应该感到尴尬。您的回答帮助我解决了类似的问题。在挠了我的头几个小时之后。 :)
【解决方案2】:

解决方法,而不是解决方案。您应该可以通过添加 -Duser.home=$HOME 作为参数来设置它。

java -Duser.home=$HOME Test

【讨论】:

  • 是的,我也是这样做的,将原始 java 重命名为 java_bin 并创建一个 shell 脚本,将这些属性添加到 java_bin 命令行。不过,我不想接受这个作为解决方案,因为必须有更好的方法。
  • strace 日志显示什么? strace -o foobar.log java 测试
【解决方案3】:

其他有保证的属性呢?如果您拨打类似以下的电话会发生什么?


   public static void printAllGuaranteedProperties() {
       printAProperty ("java.version", "Java version number");
       printAProperty ("java.vendor", "Java vendor specific string");
       printAProperty ("java.vendor.url", "Java vendor URL");
       printAProperty ("java.home", "Java installation directory");
       printAProperty ("java.class.version", "Java class version number");
       printAProperty ("java.class.path", "Java classpath");
       printAProperty ("os.name", "Operating System Name");
       printAProperty ("os.arch", "Operating System Architecture");
       printAProperty ("os.version", "Operating System Version");
       printAProperty ("file.separator", "File separator");
       printAProperty ("path.separator", "Path separator");
       printAProperty ("line.separator", "Line separator");
       printAProperty ("user.name", "User account name");
       printAProperty ("user.home", "User home directory");
       printAProperty ("user.dir", "User's current working directory");
    }
    public static void printAProperty (String propName, String desc) {
       System.out.println ("Value for '" + desc + "' is '" + System.getProperty(propName) + "'.");
    }

【讨论】:

    【解决方案4】:

    wds 在他/她的评论中是正确的。 user.home 值似乎取自 /etc/passwd。 您的用户在/etc/passwd 中的哪一行?

    如果我将条目更改为/home/nonexisting,则Test 类将打印/home/nonexisting。你碰巧在 /etc/passwd 中有 ? 吗?

    【讨论】:

    • 我的用户不在 /etc/passwd 中。不过,我的同事在他的机器上也是如此,但它在那里工作。
    • @AngeloNeuschitzer 该线程已有 2.5 年历史,我不再为遇到此问题的公司工作,但不,我没有,因为我没有系统的 root 权限。请注意,这个问题也有一个 2.5 年前的解决方案;)
    【解决方案5】:

    这真的很有趣。看起来 user.home 属性不是取自 $HOME 环境变量。 我试过这个:

    $ echo $HOME && java Test && unset HOME && echo $HOME && java Test
    /home/grzole
    /home/grzole
    
    /home/grzole
    

    请注意,shell 会忘记 HOME 变量值,但 Java 不会。

    编辑: 我怀疑 Java 只是采用 /home/ 前缀并添加用户名。 考虑一下:

    # adduser b
    ...
    # rm -fr /home/b
    # su - b
    No directory, logging in with HOME=/
    $ cd /tmp/jb
    $ java Test
    /home/b
    

    也许您的文件系统中根本没有/home 目录?

    【讨论】:

    • 请注意,Java 正在做一些比将用户名附加到“/home/”更复杂的事情。我的 Linux 网络机器上的主目录位于“/nethome”
    • ... 我猜 - Java 报告 /nethome/b 是各自的主目录?
    • 我没有相应的权限在我们项目的服务器上执行第二个块中的所有操作,但我不得不假设,因为 java bug 数据库条目(链接在其他答案/cmets) 表示 Java 可以回退到 LDAP,具体取决于系统配置。
    【解决方案6】:

    需要仔细研究本机代码以弄清楚到底发生了什么。 user.home 变量由 Linux 系统中的“PAM”模块设置,如果正在使用的模块动态生成这些并且 Java 实现试图在不显式使用 PAM 的情况下获取值,那么行为是不可预测的,因此“?”

    【讨论】:

      【解决方案7】:

      为了完整起见,如果有问题的系统配置为使用 LDAP 身份验证(而不是 /etc/passwd),则此错误报告中概述的问题可能是问题:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6972329。确保为您的系统安装了适当的 libnss_ldap.so(例如:用于 32 位 Java 的 32 位 LDAP 库)。一些可能有助于确定这一点的命令可能是:

      > rpm -qa | grep ldap
      nss-pam-ldapd-0.7.5-14.el6_2.1.x86_64   # Note x86_64 bit version installed
      
      > ls -l /lib64/libnss_ldap*
      -rwxr-xr-x. 1 root root 44328 Jan  3  2012 /lib64/libnss_ldap.so.2
      # ^^^ note 64 bit version installed.
      
      > ls /lib/libnss_ldap*
      ls: cannot access /lib/libnss_ldap*: No such file or directory
      # ^^^ Indicates 32 bit version is not installed!
      

      【讨论】:

      • 向@PascalThivent 的支持,他之前提供了链接,让我意识到了这种可能性。
      • 这应该更通用。检查/etc/nsswitch.conf,并获取用于passwd 服务的提供者的完整列表。然后确保所有对应的/lib/libnss_xxx 库也安装了 32 位。我在sss 提供程序上遇到了同样的问题。有时也很难找到合适的包。
      【解决方案8】:

      我遇到了同样的问题,在@digitalbreed 的回答中,我发现了一个类似但不同的解决方案。就我而言,一切都是 64 位的。但是,我注意到问题仅在从命令行运行时出现,而如果我从 IntelliJ 尝试它,它工作正常 - 因为它使用了不同的 JDK。

      因此,我从 CLI 中删除了我正在使用的 JDK(openjdk-15.0.1-ga,由 nix-env 提供),并将 IntelliJ 的 JDK(openjdk-16.0.1)添加到 PATH,现在可以了。

      【讨论】:

        【解决方案9】:

        我遇到了同样的问题。如上所述,问题在于,32 位 Java 还需要安装 32 位 ldap 库。如果不是,则发生描述的错误。

        安装 libnss_ldap.so.2 和依赖包解决了这个问题。

        【讨论】:

          【解决方案10】:

          我在运行mvn docker 镜像时遇到了这个问题,它在后台运行 java 并共享这个问题。我认为this answer 的诊断正确,但解决方案对我不起作用。我必须在两个地方安装一个本地 .m2 文件夹才能让文件夹正确缓存。它想将/root/.m2 用于某些事情,而将/scratch/?/.m2 用于其他事情,所以我将它们都安装了

          mkdir -p root/.m2
          docker run --rm -it \
            --user $(id -u):$(id -g) \
            -v `pwd`:/scratch --workdir /scratch -e HOME=/scratch \
            -v `pwd`/root:/root/ -v `pwd`/root:'/scratch/?' \
            maven:3-jdk-11 mvn package
          

          【讨论】:

            猜你喜欢
            • 2021-07-27
            • 1970-01-01
            • 1970-01-01
            • 2017-03-07
            • 1970-01-01
            • 1970-01-01
            • 2010-12-02
            • 2013-09-13
            • 2011-12-29
            相关资源
            最近更新 更多