Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

String array command with SystemCommandTasklet #752

Closed
spring-projects-issues opened this issue Dec 12, 2019 · 6 comments
Closed

String array command with SystemCommandTasklet #752

spring-projects-issues opened this issue Dec 12, 2019 · 6 comments

Comments

@spring-projects-issues
Copy link
Collaborator

dgray16 opened BATCH-2863 and commented

Hi. Using this chance I want to thank you for Spring Batch, it is amazing :)

Now, directly to the topic.

 

I want to use

org.springframework.batch.core.step.tasklet.SystemCommandTasklet 

but there an issue.

 

There is method:

org.springframework.batch.core.step.tasklet.SystemCommandTasklet#setCommand

which accepts

java.lang.String

 

My task is simple: run network packet analyzer Wireshark before processing is started.

Bash command looks like this:

 

/bin/bash -c tshark -i enp1s0 -w ~/Documents/log.pcap -f "host 8.8.8.8"

 

The problem is that

java.util.StringTokenizer#StringTokenizer(java.lang.String)

is about to split provided String with Bash command into array, after it command is not working.

 

In this case helps a lot another method

java.lang.Runtime#exec(java.lang.String[], java.lang.String[], java.io.File)

So if I split manually command into this:

new String[] { "/bin/bash", "-c", "tshark -i enp1s0 -w ~/Documents/log.pcap -f \"host 8.8.8.8\""}

Works perfectly.

 

If there is tricky way to hack

java.util.StringTokenizer#StringTokenizer(java.lang.String)

to make it work with my example, I suggest to add JavaDoc above

org.springframework.batch.core.step.tasklet.SystemCommandTasklet#setCommand

 

If not, I suggest to provide possibility to use both forms, String[] + String.

 

And one more thing, there may be opportunity to run sh script by single String method (did not test it), but I am not interested in it. I am interested only in hardcoded bash command.

 

As a workaround for it right now I have written this code:

Tasklet tasklet = (contribution, chunkContext) -> {
    new ProcessBuilder("/bin/bash", "-c", "tshark -i enp1s0 -w ~/Documents/log.pcap -f \"host 8.8.8.8\"").start();
    return RepeatStatus.FINISHED;
};

 

In any case I am ready to create PR based on discussion here if that will be needed.

 


Affects: 4.2.1

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Dec 12, 2019

Mahmoud Ben Hassine commented

SystemCommandTasklet#setEnvironmentParams is what you are looking for:

SystemCommandTasklet systemCommandTasklet = new SystemCommandTasklet();
systemCommandTasklet.setCommand("/bin/bash");
systemCommandTasklet.setEnvironmentParams(new String[] {"-c", "tshark -i enp1s0 -w ~/Documents/log.pcap -f \"host 8.8.8.8\""});

The array of arguments will be passed as parameters to the command when calling java.lang.Runtime#exec behind the scene.


EDIT: The example above is incorrect. setEnvironmentParams is meant for environment variables, not for command arguments. Apologies for the confusion as I seem to have misread the Javadoc of java.lang.Runtime#exec. Since SystemCommandTasklet is using the convenience method java.lang.Runtime#exec which takes a single String for the command and its arguments, the expected way to pass arguments is as follows:

SystemCommandTasklet systemCommandTasklet = new SystemCommandTasklet();
systemCommandTasklet.setCommand("/bin/bash -c tshark -i enp1s0 -w ~/Documents/log.pcap -f \"host 8.8.8.8\"");

The Javadoc of setCommand should be more precise about the expected input and how it will be tokenized if any. Now if the default tokenization done behind the scene by java.lang.Runtime#exec fails or does not work as expected (as initially reported in this issue), Spring Batch can't really help for that. I believe setCommand should accept a vararg of Strings for the command and its arguments to allow the user to specify tokens as needed.

@spring-projects-issues
Copy link
Collaborator Author

@philippe-tr
Copy link

Passing command arguments as environment parameters seems counter-intuitive. Does this mean the intent of SystemCommandTasklet#setEnvironmentParams is both command arguments and environment parameters?

@hpoettker
Copy link
Contributor

I wouldn't expect that passing command arguments to setEnvironmentParams actually works. The array of environment parameters is passed as is to ProcessBuilder::environment. The example arguments above should get silently (compatibility with Java 4 ...) ignored there since they don't contain a =.

@philippe-tr
Copy link

philippe-tr commented May 25, 2021

I have ideas for how to support this while maintaining backward compatibility. I also want to do it in a way that works for the requirements in BATCH-2318

philippe-tr pushed a commit to philippe-tr/spring-batch that referenced this issue May 26, 2021
setCommand now supports passing in an array of strings. When a single
string is supplied, it is tokenized by the Runtime#exec method. When an
array of strings is supplied, the array is supplied as is to the
Runtime#exec method in which case no tokenization takes place.

Resolves spring-projects#752
@fmbenhassine
Copy link
Contributor

The example in my previous comment is incorrect, I edited that comment to clarify things. Apologies for the confusion.

I believe setCommand should accept a vararg of Strings for the command and its arguments (similar to java.lang.ProcessBuilder#command(java.lang.String...)). The PR #3967 goes in the right direction to solve this issue.

@fmbenhassine fmbenhassine linked a pull request Aug 5, 2021 that will close this issue
philippe-tr pushed a commit to philippe-tr/spring-batch that referenced this issue Aug 6, 2021
setCommand now supports passing in an array of strings. When a single
string is supplied, it is tokenized by the Runtime#exec method. When an
array of strings is supplied, the array is supplied as is to the
Runtime#exec method in which case no tokenization takes place.

Resolves spring-projects#752
@fmbenhassine fmbenhassine added this to the 5.0.0 milestone May 4, 2022
@fmbenhassine fmbenhassine changed the title String array command with SystemCommandTasklet [BATCH-2863] String array command with SystemCommandTasklet May 4, 2022
@fmbenhassine fmbenhassine removed the status: waiting-for-triage Issues that we did not analyse yet label May 4, 2022
@fmbenhassine fmbenhassine modified the milestones: 5.0.0, 5.0.0-M6 Aug 31, 2022
@fmbenhassine fmbenhassine modified the milestones: 5.0.0-M6, 5.0.0-M7 Sep 20, 2022
@fmbenhassine fmbenhassine modified the milestones: 5.0.0-M7, 5.0.0-M8 Oct 4, 2022
fmbenhassine added a commit that referenced this issue Oct 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants