31

In my Java command-line arguments, any characters after space get ignored. For example,

java test.AskGetCampaignByName "Dummy books"

I get the first argument (args[0]) as "Dummy" only. Single quotes also do not help. Is there a workaround/fix for this? Could it be because of my terminal settings?

My $TERM is xterm, and $LANG is "en_IN".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ashweta
  • 1,437
  • 3
  • 17
  • 19

5 Answers5

60

The arguments are handled by the shell (I assume you are using Bash under Linux?), so any terminal settings should not affect this.

Since you already have quoted the argument, it ought to work. The only possible explanation I can think of is if your java command is a wrapper script and messes up the escaping of the arguments when passing on to the real program. This is easy to do, or perhaps a bit hard to do correctly.

A correct wrapper script should pass all its arguments on as ${1+"$@"}, and any other version is most likely a bug with regards to being able to handle embedded spaces properly. This is not uncommon to do properly, however also any occurrences of $2 or similar are troublesome and must be written as "$2" (or possibly ${2+"$2"}) in order to handle embedded spaces properly, and this is sinned against a lot.

The reason for the not-so-intuitive syntax ${1+"$@"} is that the original $* joined all arguments as "$1 $2 $3 ..." which did not work for embedded spaces. Then "$@" was introduced that (correctly) expanded to "$1" "$2" "$3" ... for all parameters and if no parameters are given it should expand to nothing. Unfortunately some Unix vendor messed up and made "$@" expand to "" even in case of no arguments, and to work around this the clever (but not so readable) hack of writing ${1+"$@"} was invented, making "$@" only expand if parameter $1 is set (i.e. avoiding expansion in case of no arguments).

If my wrapper assumption is wrong you could try to debug with strace:

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

and find out what arguments are passed to execve. Example from running "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
  • 26,565
  • 10
  • 94
  • 165
  • 2
    Thanks a lot hlovdal! That was exactly the case. We generate an executable through ant build that sets the classpaths etc. And we were using "java @" in the script. Substituting your ${1 + "@"} solved the problem. Sorry for misleading by using java directly in my example. I assumed it means the same – ashweta Apr 13 '09 at 13:45
  • 1
    Very well thought-out, thorough answer. +1 for the suggestion to use strace. Your answer solved my problem perfectly. – Aquarelle Mar 08 '21 at 22:27
0

In case your program needs more than positional arguments (= when the command line usage is important), you should consider options and switches. Apache Commons has a great library for this.

nxadm
  • 2,079
  • 12
  • 17
0

It sounds like you are using a operating system distribution where the java command available to the user is a wrapper which finds the right JVM "somewhere" and invokes it accordingly.

If so, it most likely does not escape the arguments properly when invoking the actual java executable.

What distribution do you use?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
  • On my Windows machine `"hello world" "hello world" "hello world"` passed as command-line arguments will be picked up as args[0 (/1) (/2)] == "hello world" and on Linux this simply does not work (i don't remember what it *does* do, as I wasn't too concerned). But I would be glad to see any solution to this. Thanks for the question. @Thorbjørn Ravn Andersen, please elaborate. How can I change the way JVM is invoked? – Peter Perháč Apr 13 '09 at 10:43
0

You just have to escape the spaces like this:

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

That worked for me.

My environment:

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.
Mohammad Ersan
  • 12,304
  • 8
  • 54
  • 77
Zarathustra
  • 2,853
  • 4
  • 33
  • 62
  • 2
    You didn't escape anything, you just broke a single argument up into two arguments which is not at all what the OP was asking for. Spaces don't need escaped, they simply need quoted. – Brad Wood Dec 30 '16 at 03:41
-3

Just reassemble the arguments in your Java program:

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • Because `java test.AskGetCampaignByName "Dummy books"` with multiple spaces between `Dummy` and `books` would fail (which Stack Overflow outputs as a single space, so you can't see it here...) – leemes Jul 16 '12 at 00:23
  • Because `java` should be getting the command-line arguments properly from the shell to begin with. – Olathe Mar 03 '13 at 14:50