问题
So, I try to export file variable:
String somePath = "/Users/me/File with whitespaces.json";
Runtime runtime = Runtime.getRuntime();
runtime.exec(String.format("$MY_FILEPATH=\"%s\"", somePath));
And I get some exception on this line:
java.io.IOException: Cannot run program "$MY_FILEPATH=/Users/me/File": error=2, No such file or directory
P.S. If I try "prepend space in file name with \", I get:
String somePath = "/Users/me/File\ with\ whitespaces.json";
Runtime runtime = Runtime.getRuntime();
runtime.exec(String.format("open %s", somePath));
And I also get some exception on this line:
The files /Users/me/File\, with\, whitespaces.json do not exist.
P.P.S If I wrap path in "", I also get exception like above
回答1:
Add: mostly dupe Why does Runtime.exec(String) work for some but not all commands?
Runtime.exec
is not a shell
- The overloads of
Runtime.exec
that take aString
tokenize at whitespace. Period. A shell tokenizes at whitespace by default but this can be overridden with quotes or backslash; inRuntime.exec
it cannot. If you want any other tokenization you have to use the overloads that takeString[]
instead. This answers the question you actually asked. For example you could do the equivalent ofopen 'path with spaces'
by:
Process p = runtime.exec (new String[] {"open", "path with spaces"});
Runtime.exec
runs programs only. Shell commands often run a program but not always.export
is a shell builtin that the shell executes but is not a program soRuntime.exec
cannot.Runtime.exec
runs programs in child processes, which is like a shell. Even if you could somehow runexport
as a child process, the change it makes would exist only in that child process. It would NOT affect the Java process or any other programs run from the Java process, just like if you use shell to doexport
in a child process -- most simply a subshell using parentheses like( export foo=bar; echo $foo ); echo $foo
-- then it is set only in the child shell process and not the parent shell, and not any other children of the parent shell.
Thus if your goal is to set an environment variable to be used by some other program(s), you cannot do that by running anything in Runtime.exec
. You can pass an environment that is modified to add (or change or delete) environment variables to some other (real) program you run with Runtime.exec
by using the overloads that take an envp
parameter -- see the javadoc -- or with ProcessBuilder
by using the environment()
method (javadoc)
But if your goal is to do the equivalent of shell's foo='path with spaces'; open "$foo"
(note quotes are needed for this to work in shell) you can't. The substitution of $foo
to path with spaces
(within a token, and thus passed as an argument) is done by the shell not by the open
program -- and Runtime.exec
is not a shell so it doesn't do this. You have to pass the path with spaces
token/argument yourself as in point 1 above, or explicitly run a shell (commonly /bin/sh
or just sh
) and give the shell the foo=...; ...$foo...
commands to execute -- and export
isn't needed since the variable is used only in the shell not the child process.
BTW even in shell you don't use a $
when you set an environment variable or shell variable, only when you use the value of a variable (or of certain other things like a command substitution or arithmetic expression).
来源:https://stackoverflow.com/questions/48425729/whitespace-in-bash-path-with-java