【问题标题】:Space in Java command-line argumentsJava 命令行参数中的空格
【发布时间】:2009-04-13 09:37:11
【问题描述】:

在我的 Java 命令行参数中,空格后面的任何字符都会被忽略。例如,

java test.AskGetCampaignByName "Dummy books"

我只将第一个参数 (args[0]) 作为“虚拟”。单引号也无济于事。 有解决方法/解决方法吗?会不会是我的终端设置的原因?

我的 $TERM 是 xterm,$LANG 是“en_IN”。

【问题讨论】:

    标签: java


    【解决方案1】:

    参数由 shell 处理(我假设您在 Linux 下使用 Bash?),因此任何终端设置都不会影响这一点。

    既然你已经引用了这个论点,它应该可以工作。我能想到的唯一可能的解释是,如果您的 java 命令是一个包装脚本,并且在传递给实际程序时会混淆参数的转义。这很容易做到,或者可能有点难以正确做到。

    正确的包装脚本应该将其所有参数作为${1+"$@"} 传递,而任何其他版本很可能是无法正确处理嵌入空格的错误。正确执行此操作并不少见,但是$2 或类似的任何出现都是麻烦的,并且必须写为"$2"(或可能${2+"$2"})才能正确处理嵌入空间,这对很多人来说是有罪的.

    不那么直观的语法${1+"$@"} 的原因是原始$* 将所有参数作为"$1 $2 $3 ..." 加入,这不适用于嵌入式空间。然后"$@" 被引入,所有参数(正确地)扩展为"$1" "$2" "$3" ...,如果没有给出参数,它应该扩展为空。不幸的是,一些 Unix 供应商搞砸了,即使在没有参数的情况下也将 "$@" 扩展为 "",为了解决这个问题,发明了编写 ${1+"$@"} 的聪明(但不那么易读)的技巧,只制作了 "$@"如果设置了参数$1,则展开(即在没有参数的情况下避免展开)。

    如果我的包装假设错误,您可以尝试使用strace 进行调试:

    strace -o outfile -f -ff -F java test.AskGetCampaignByName "Dummy books"
    

    并找出传递给execve 的参数。运行“strace /bin/echo '1 2' 3”的示例:

    execve("/bin/echo", ["/bin/echo", "1 2", "3"], [/* 93 vars */]) = 0
    brk(0)                                  = 0x2400000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f420075b000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f420075a000
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    open("/usr/lib64/alliance/lib/tls/x86_64/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
    stat("/usr/lib64/alliance/lib/tls/x86_64", 0x7fff08757cd0) = -1 ENOENT (No such file or directory)
    open("/usr/lib64/alliance/lib/tls/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
    ...
    

    【讨论】:

    • 非常感谢 hlovdal!情况正是如此。我们通过 ant build 生成一个可执行文件来设置类路径等。我们在脚本中使用了“java @”。替换你的 ${1 + "@"} 解决了这个问题。很抱歉在我的示例中直接使用 java 产生误导。我认为它的意思是一样的
    • 经过深思熟虑的彻底回答。 +1 建议使用 strace。你的回答完美解决了我的问题。
    【解决方案2】:

    如果您的程序需要的不仅仅是位置参数(= 当命令行使用很重要时),您应该考虑选项和开关。 Apache Commons 为此提供了一个很棒的library

    【讨论】:

      【解决方案3】:

      你只需要像这样逃避空格:

      normal String: "Hello World!"
      escaped String: "Hello" "World!"
      

      这对我有用。

      我的环境:

      23:39:19 Zarathustra@thora:/Users/Zarathustra~$bash -version
      GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
      Copyright (C) 2007 Free Software Foundation, Inc.
      

      【讨论】:

      • 您没有逃避任何事情,您只是将一个参数分解为两个参数,这根本不是 OP 所要求的。空格不需要转义,它们只需要引用。
      【解决方案4】:

      听起来您正在使用操作系统发行版,其中用户可用的 java 命令是一个包装器,它在“某处”找到正确的 JVM 并相应地调用它。

      如果是这样,它很可能在调用实际的 java 可执行文件时没有正确转义参数。

      你使用什么发行版?

      【讨论】:

      • 在我的 Windows 机器上 "hello world" "hello world" "hello world" 作为命令行参数传递将被拾取为 args[0 (/1) (/2)] == "hello world" 而在 Linux 上这只是不起作用(我不记得它做了什么,因为我不太担心)。但我很高兴看到任何解决方案。谢谢你的问题。 @Thorbjørn Ravn Andersen,请详细说明。如何更改 JVM 的调用方式?
      【解决方案5】:

      只需在您的 Java 程序中重新组合参数即可:

      StringBuilder allArgs = new StringBuilder();
      for (int i=0; i < args.length; i++)
      {
          //System.out.println("arg"+i+": "+args[i]);
          allArgs.append(args[i]+" ");
      }
      // Parse out the args the way you wish using allArgs
      

      【讨论】:

      • 因为java test.AskGetCampaignByName "Dummy books"Dummybooks 之间有多个空格会失败(堆栈溢出输出为单个空格,所以你在这里看不到...)
      • 因为java 应该从 shell 中正确获取命令行参数。
      猜你喜欢
      • 2014-05-22
      • 2018-12-14
      • 2019-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-10
      • 2017-03-04
      • 2019-06-11
      相关资源
      最近更新 更多