2

I am working with bash. I have a file F containing the command-line arguments for a Java program, and I need to store both outputs of the Java programs, i.e., output on standard output and the exit value. Storing the standard output works via

cat F | xargs java program > Output

But xargs does not give access to the exit-code of the Java program. So well, I split it, running the program twice, once for standard output, once for the exit code --- but getting the exit code and running it correctly seems impossible. One might try

java program $(cat F)

but that doesn't work if F contains for example " ", namely one command-line argument for program which is a space. The problem is the expansion of the argument $(cat F).

Now I don't see a way to get around that problem? I don't want "$(cat F)", since I want that $(cat F) expands into many strings --- but I don't want further expansion of these strings.

If on the other hand there would be a better xargs, giving access to the original exit value, that would solve the problem, but I am not aware of that.

Oliver Kullmann
  • 253
  • 1
  • 7
  • 1
    Do you need the status code and the output in the same file? How do you know where the output of the next file begins? – rici Jan 22 '15 at 02:25
  • The status code I just need to store in a variable (in the bash-script). – Oliver Kullmann Jan 22 '15 at 02:48
  • What does the file `F` look like? How do you handle arguments which have whitespace in them? Is it one argument per line, or..? – rici Jan 22 '15 at 04:45

3 Answers3

3

Does this do what you want?

cat F | xargs bash -c 'java program "$@"; echo "Returned: $?"' - > Output

Or, as @rici correctly points out, avoid the UUOC

xargs bash -c 'java program "$@"; echo "Returned: $?"' - < F > Output

Alternatively something like (though I haven't thought through all the ramifications of doing this so there may be a reason this is a bad idea).

{ sed -e 's/^/java program /' F | bash -s; echo "Returned $?"; } > Output

This lets you store the return code in a variable the xargs versions do not (at least not outside the xargs-spawned shell.

sed -e 's/^/java program /' F | bash -s > Output; ret=$?

To use a ${program} shell variable just expand it directly.

xargs bash -c 'java '"${program}"' "$@"; echo "Returned: $?"' - < F > Output

sed -e 's/^/java '"${program}"' /' F | bash -s > Output; ret=$?

Just beware of characters that are "magic" in the replacement of the s/// command.

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • 2
    uuoc. `xargs ... < F > output` – rici Jan 22 '15 at 02:31
  • @rici Copied from OP without thinking about it. Thanks. – Etan Reisner Jan 22 '15 at 02:33
  • Sorry, it took me too long to figure out the details. In principle it works (thanks!), the two xargs-versions, but now I need to store the return-value in a variable, and instead of the hard-coded "program" I need ${program}; seems a bit subtle to me. – Oliver Kullmann Jan 22 '15 at 03:20
  • 1
    I am a bit worried by the sed-solution, and so I just save the returned value to a file. That solved the problem now! – Oliver Kullmann Jan 22 '15 at 03:51
  • @OliverKullmann I'm not sure that's meaningfully different but sure. I almost suggested that in the post but didn't figure it was worth it. – Etan Reisner Jan 22 '15 at 05:02
0

I'm afraid the question is really not very clear, so I will make the assumptions here explicit:

  1. The file F has one argument per line, with all whitespace other then newline characters being significant, and with no need to replace backslash escapes such as \t.

  2. You only need to invoke the java program once, with all of the arguments.

  3. You need the exit status to be preserved.

This can be done quite easily in bash by reading F into an array with mapfile:

# Invoked as: do_the_work program < F > output
do_the_work() {
  local -a args
  mapfile -t args
  java "$@" "${args[@]}"
}

The status return of that function is precisely the status return of the java executable, so you could capture it immediately after the call:

do_the_work my_program
rc=$?

For convenience, the function allows you to also specify arguments on the command line; it uses "$@" to pass all the command-line arguments before passing the arguments read from stdin.

rici
  • 234,347
  • 28
  • 237
  • 341
0

If you have GNU Parallel (and do not mind extra output on STDERR):

cat F | parallel -Xj1 --halt 1 java program > Output
echo $?
Ole Tange
  • 31,768
  • 5
  • 86
  • 104