I am trying to execute "normalize-audio out/*.wav" command from java. for single file as follows,
Runtime.getRuntime().exec("normalize-audio 0002.wav");
it works fine. but, when i use,
Runtime.getRuntime().exec("normalize-audio out/*.wav");
it says:
file *.wav: No such file or directory
any idea, how i can achieve this?
The expansion of the * glob is, when you call your script "normally", carried out by the shell. That is, bash or cmd.exe or whatever you're using, sees the * as a special character and carries out some logic to expand it into the set of actual filenames that match. Then, the script is actually executed passing in these explicit filenames as the argument(s).
So, you have two options:
Do the same yourself. Query the files in the appropriate directory, find all of them that match the *.wav pattern, then build these up into the argument string. So instead of invoking exec passing *.wav as an argument to your script, you'd end up passing something like 0001.wav 0002.wav 0007.wav.
Get bash to do it. If you invoke bash as the program, and then pass in your command as a string, then bash will do its glob expansion as normal. This would look something like Runtime.getRuntime().exec("bash -c normalize-audio out/*.wav");. The downsides to this are firstly that you're now much less portable (you have requirements about third-party software existing on the PATH), and also that you can get into all sorts of tangles with escaping quotes in your invocation.
Related
I have the following simple java program:
import java.util.Arrays;
public class Arguments
{
public static void main(String [] args)
{
System.out.println("args: "+Arrays.toString(args));
}
}
When I execute this in powershell using the following command: java Arguments "*.java" the string received in the program is not "*.java" but a comma-separated list of all java files in the current directory. And if there are no java files in the current directory the string received is "*.java".
I want to know why this is happening and how to pass a string as it is without converting it.
Update: java Arguments '"*".java' and java Arguments `"*.java`" did the work but this creates the same problem when executed in cmd. Can anyone explain why this is happening? Is there any common solution for both PowerShell and cmd?
It is not PowerShell (nor cmd.exe) that interprets "*.java" as a filename pattern and expands (resolves) it to the matching files, known as globbing in the Unix world.
(You would only get that behavior if you used *.java - i.e., no quoting - in PowerShell Core on Unix-like platforms, but never with a quoted string such as "*.java" or '*.java', and even without quoting never on Windows).
Apparently, it is legacy versions of java.exe on Windows that automatically perform the globbing on unquoted arguments, in an apparent attempt to emulate the behavior of POSIX-like shells such as Bash on Unix.
As of (at least) JDK 12, this behavior no longer seems to be effect, at least not by default.
The linked answer suggests that in earlier versions there may be a system property that controls the behavior, but it's unclear what its name is.
Generally, the syntax java -D<systemPropName>=<value> ... can be used to set a system property on startup.
Therefore, you have the following options:
Upgrade to a Java version that no longer exhibits this behavior (by default).
In legacy versions, find the relevant system property name that disables the behavior and use the syntax shown above.
Use shell-specific quoting, as shown below.
Using quoting to prevent globbing:
To prevent java.exe from performing globbing, the invocation command line must ultimately contain "*.java", i.e., the argument must be enclosed in double quotes.
Unfortunately, there is no common syntax that works in both PowerShell and cmd.exe:
cmd.exe:
cmd.exe passes double-quoted arguments through as-is, so the following is sufficient:
java Arguments "*.java"
PowerShell:
PowerShell, by contrast, performs re-quoting as needed behind the scenes (see this answer for more information).
Since an argument with content *.java normally does not require quoting when you pass it to an external program, PowerShell translates both "*.java" and '*.java' to unquoted *.java in the command line that is ultimately used behind the scenes - which is what you experienced.
There are two ways around that:
Use java Arguments '"*.java"', i.e., embed the " chars. in the argument, inside a literal string ('...').
Use java Arguments --% "*.java"; --% is the stop-parsing symbol (PSv3+), which instructs PowerShell to pass the remainder of the command line through as-is (except for expanding cmd.exe-style environment-variable references).
I'm running this command:
find /tmp/thumbnailgenerator/processor -maxdepth 1 -amin +1 -type f -iname 'a*' -delete
which works as expected when run from the command line. But when run as a singular command in Java via Runtime.getRuntime.exec(String command), the files are not deleted. (Yes they are one minute old.) Also when run as a command array cmdarray that joins to the above string via StringUtils.join(cmdarray, ' '), it still does not work.
I suspect this has to do with the glob expansion since I know a common mistake in using Runtime.exec is to assume it does glob expansion like bash does, but deleting * does not help (it still won't delete file a).
This has to do with how the first round of processing is performed by bash v. exec, but not exactly glob expansion. Remove the ' ' around the filename and it should work. In bash, you use those quotes to prevent bash from expanding the glob. However single quote has no special meaning to exec either, so those are passed raw to the find command too. You want find to see a*. In bash, this means you must type 'a*'. But in exec, it means you must type a* or else find will see 'a*'.
I have a Perl file which is actually calling some jar files and I'm trying to make it an all Java program and remove the Perl. So I came up through this lines which is:
$blammercommand="$javapath $javaparams -jar $blammerpath -conf $blammerconf $blammerparams -cpu $cpu -i \"".$tmpdir."blastresults/*.bls\" -db \"$infilename $blastdb\"";
(system($blammercommand)==0) or die "unable to do $blammercommand\n";
I've already decompressed the jar files and added the source codes to my Eclipse project and have access to the main function of the related jar file. I'm just trying to pass the arguments as inputs.
My problem is exactly here that I don't know what "\"".$tmpdir."blastresults/*.bls\"" and "\"$infilename $blastdb\"" mean. I know what exactly each one of this variables are but I don't know how those \, / and * are working and how should I convert them to Java.
Those are just shell escaping and shell globbing. Literally written, it would look like this:
${javapath} ${javaparams} -jar ${blammerpath} -conf ${blammerconf} ${blammerparams} -cpu ${cpu} -i "${tmpdir}blastresults/*.bls" -db "${infilename} ${blastdb}
Here, the syntax ${name} is meant to indicated an inserted value of the variable. The system command in Perl runs a system command through the default system shell, usually something like bash. The quotes are used to make several space-separated strings "stick together" as one argument. The * is a wildcard, which is replaced by all filenames in a given directory.
I have a Java program utility that I want to execute as a command in cmd. I added the location to the PATH variable, but java programs needs to be executed using java - jar "...". How do I shorten that to just the program name, like mysql or netstat?
Update:
I neglected to mention that this java program takes arguments of its own to handle its tasks, so the batch program would need to pass the arguments passed to it over the the java program. I'm not skilled enough in batch to know how to do this.
~Jacob
You could create a batch file or bash script (depending upon your OS) that calls the program with the proper java -jar commands, and simply name the batch (or bash) script whatever you would like to enter as the command. Place this in a directory that is in your PATH variable, and have at it.
Edit: Read this for info on how to parse command line parameters in batch scripts. Just take the parameters passed to the batch file, parse them, and pass them to your jar file with:
java -jar jarfile.jar param1 param2 ...
So for example, lets's assume that your program takes two arguments. Your script could then be as follows:
java -jar jarfile.jar %1 %2
I am not an expert in batch files by any means, so there is probably a more proper way to do this. That being said, why over complicate things?
With Launch4J you can wrap a Java program in a standalone executable file. I'm not going to copy their (long) feature list here, but definite highlights are the numerous ways presented to customize the resulting exe, its small size, the fact that it's open source and its permissive license that allows commercial usage.
I am trying to do something using system exec in Java
Runtime.getRuntime().exec(command);
Surprisingly everything that is related with paths, directories and files is not working well
I don't get why and just want to know is there any alternatives?
The alternative is to use the ProcessBuilder class, which has a somewhat cleaner interface, but your main problem is probably related to how the OS processes command lines, and there isn't much Java can do to help you with that.
As noted above, cd is a shell builtin. i.e. it's not an executable. You can determine this using:
$ which cd
cd: shell built-in command
As it's not a standalone executable, Runtime.exec() won't be able to do anything with it.
You may be better off writing a shell script to do the shell-specific stuff (e.g. change the working directory) and then simply execute that shell script using Runtime.exec(). You can set PATH variables etc. within your script and leave Java to simply execute your script.
One thing that catches people out is that you have to consume your script's stdout/stderr (even if you throw it away). If you don't do this properly your process will likely block. See this SO answer for more details.
The exec() method can take three arguments. The third is the directory your subprocess should use as its working directory. That solves your "cd" problem, anyway.