9

So, basically, I want to successfully pass an arbitrary string in java that could contain special characters (such as tabs). Here's this code sample:

String tab = "\t"; 
//String tab = args[0];
String full = "hi"+tab+"hi"+tab+"bye";
String[] parts = full.split(tab);
String print = "";
for (String s : parts) {
    print += s + tab;
}
print = print.substring(0, print.length()-tab.length());
System.out.println(print);

Split successfully recovers the parts regardless of how the variable tab is defined. However, when it's actually printed, defining tab manually (the non-commented out version) prints it as expected, with tab characters. However, passing through command line causes it to actually print "\t" (the same as if the String was actually "\\t" for instance).

I'm primarily using bash, and would be happy for any bash-specific ideas, though would be happier if it also included a general explanation of what's happening. Why is the regex of both the same while the String literal is different?

bash invocation of the program:

ARGS="$X $Y $Z \t"

java -cp $CLASSPATH $MEM $PROGRAM $ARGS 2> "${PROGRAM##*.}-error.log" > "${PROGRAM##*.}-out.log"

The answer provided here does actually mostly work for my purposes, is fairly readable, and generally only fails on fairly unusual things: "\\\t", for instance: https://gist.github.com/uklimaschewski/6741769

bhaall
  • 91
  • 1
  • 3

4 Answers4

7

The tab that you defined in code is a single-character string (since "\t" is an escape sequence). From the command line you get a two-characters string, as bash doesn't handle "\t" as the tab character.

To pass that from command line, you can use echo -e which supports escape sequences like \t (or \n and a few others):

$ java Main "$(echo -en '\t')"
Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
  • 1
    In Bash, you can do that more elegantly with C-string syntax; `java Main $"\t"` – tripleee Oct 31 '16 at 15:47
  • java did not seem to capture the argument for the one in the answer. For the second, java captures the bash argument as a string literal – bhaall Oct 31 '16 at 18:32
4

The simplest by far is:

java my.package.Main $'\t'
alamar
  • 18,729
  • 4
  • 64
  • 97
2

If you pass '\t' or "\t" on your command line, it causes a literal backslash followed by a t to be passed to your command:

$ echo -n '\t' | xxd
00000000: 5c74                                     \t

$ echo -n "\t" | xxd
00000000: 5c74                                     \t

You can type a tab on your command line using Ctrl-v then Tab:

$ echo -n '     ' | xxd
00000000: 09                                       .

(That wide space is a tab character, not lots of spaces).

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • I tried typing a literal tab, and java didn't seem to capture it as an argument. I'm maybe not entirely sure what you're suggesting – bhaall Oct 31 '16 at 17:41
2

To pass a tab as an argument from bash, you can do any of the following:

mycommand $'arg\tcontaining\ttabs'
Which works because $'' in bash interprets escape sequences.

mycommand 'argctrl-vtabcontainingctrl-vtabtabs'
Which works because ctrl-v causes the next character typed to be inserted literally rather than being interpreted.

mycommand "$(printf 'arg\tcontaining\ttabs')"
Which works, in bash and other shells, because printf interprets backslash-escaped characters in its first argument.

Eric
  • 1,431
  • 13
  • 14
  • I tried that, but java captured it as a string literal and did not split on it correctly – bhaall Oct 31 '16 at 17:42
  • Are you certain you are using `bash` and not something like `dash`? Did the `printf` version work for you? – Eric Nov 01 '16 at 00:59