ExecuteCommandLine in OH3 not working

All,

I have a similar problem and usually successfully “translated” to OH 3 like:

executeCommandLine(Duration.ofSeconds(9), "sudo", "/bin/chown", "-R", "openhab:openhabian", "/var/www/upload/squirrel/")

However, I truggle with this execution to get the local temperature at our Car:

var String request = "curl" + " -s" + " http://api.openweathermap.org/data/2.5/weather?lat=" + Car_Loc_Lat.state.toString + "&lon=" + Car_Loc_Lon.state.toString + "&APPID=" + W_OWM_Key.state.toString + ""
logInfo("+++ CAR", "Car: Car's Temp request String (request) is: " + request)
var String json = executeCommandLine(Duration.ofSeconds(10), request)

The output string of “request” looks ok and returns the right result in a browser.
However, I get:

Failed to execute commandLine '[curl -s http://api.openweathermap.org/data/2.5/weather?lat=xxx&lon=xxx&APPID=yyy]'

Any suggestion would be greatly appreciated.

I’m not an expert, but I think the issue is that you are passing it as one string. Where there is whitespace separators in the string, all of the components either side of the whitespace have to be passed as separate parameters for it to work.

You are building and passing a single long string containing the whitespace separators, which I don’t think will work.

I think you would need something like -

var String json = executeCommandLine(Duration.ofSeconds(10), "curl", "-s", "http://api.openweathermap.org/data/2.5/weather?lat=" + Car_Loc_Lat.state.toString + "&lon=" + Car_Loc_Lon.state.toString + "&APPID=" + W_OWM_Key.state.toString)

This is the approach you took in your first example that worked.

Thank you Trevor.

In comparison to my capabilities almost everybody here is an expert :wink:

So, I will try your suggestion.
However, doesn’t this create a continuous string as well:

Anyway - I will try and post the results here.

I feel exactly the same way :slightly_smiling_face:

Based on the example you gave, there is no space in that part of the string, so I don’t think it needs breaking into separate parameters. If I’m correct, you only need to break where there are spaces (whitespace) in the command line.

Now I got what you mean - and I see the difference.
You are absolutely right!
It works flawlessly.
Thank you very much!

I’m having also some issues with my executeCommands. :sob:

executeCommandLine("/bin/sh -c (sed -i '1s;^;" + currentTime + " Groot waterverlies? " + waterVerschil + " l \\n " + ";' /var/log/openhab/belangrijk.log)")

But before attacking the sed part, I wanted to have a small working script. What I did as test, was the following. Not sure why it won’t work :blush:

rule "Test 1"
when
        Item TestKnop1 changed
then
        logInfo("TEST", "...Test start...")
        executeCommandLine(Duration.ofSeconds(1), "/usr/bin/sudo", "/bin/echo", "TEST", ">>", "/tmp/test")
        logInfo("TEST", "...Test end ...")
end

I tried already with other files, without full path or sudo…

I also can’t get that to work and I don’t get any error messages in the logs.

A little bit of searching suggests that the exec binding doesn’t work well (or possibly at all) with either redirects or pipes.

See -
https://community.openhab.org/t/rule-issue/106732/9
https://community.openhab.org/t/send-the-value-from-a-slider-to-a-script-py/103782/29
https://community.openhab.org/t/concatenate-inside-exec-command/105983/21

I’d suggest getting a short script to work that doesn’t use a redirect or pipe as a starting point.

Did you try it also without the timeout part?
The timeout should be used when you need the response from your execution.
Therefore the reponse has to be written into a variable.
Maybe thats already the reason for failing here.

If you just want to execute a script and it doesn’t matter what the reponse is, you should omit the duration parameter.

OK, new test. The file is been created. But the text isn’t added.
So it looks liks >, >> or | is giving some issues…

rule "1. Test"
when
        Item TestKnop1 changed
then
        logInfo("TEST", "...Test start...")
        executeCommandLine("touch", "/tmp/test")
        executeCommandLine("echo", "TEST", ">", "/tmp/test")
        logInfo("TEST", "...Test end ...")
end

File that’s been created:

-rw-r--r-- 1 openhab openhab 0 Jan  8 11:12 /tmp/test

I’ve also tried to changed that file rights, but no luck, nothing is been added…

I do not have much experience in java code.
The source code of executecommandLine to me looks like redirecting STDOUT and STDERR is inhibited:

    public static void executeCommandLine(String... commandLine) {
        try {
            new ProcessBuilder(commandLine).redirectError(Redirect.DISCARD).redirectOutput(Redirect.DISCARD).start();
        } catch (IOException e) {
            logger.warn("Error occurred when executing commandLine '{}'", commandLine, e);
        }
    }
1 Like

I also have issues like @brononius above and I suspect the \n to cause the issue - but it’s just a guess.

I would like to execute this:

executeCommandLine(Duration.ofSeconds(10),  "/bin/ls", "/var/www/upload/abus", "-1tr", "|", "head", "-n", "-3000", "|", "xargs", "-d", "'\n'", "/bin/rm", "-f", "--")

it works flawlessly in bash using:

/bin/ls /var/www/upload/abus -1tr | head -n -3000 | xargs -d '\n' /bin/rm -f --

any idea what might be wrong?

I tried it with ‘\\n’ already

With executeCommandLine you can only start one program with arguments.
Starting multiple programs (with redirection and pipes) is a function of a command shell.

So you must put your

/bin/ls /var/www/upload/abus -1tr | head -n -3000 | xargs -d '\n' /bin/rm -f --

line in a sh file and execute this.

Also only a guess from side, maybe you should try quoting the \n with a backslash
So it should look like this in the rule:

executeCommandLine(Duration.ofSeconds(10), “/bin/ls”, “/var/www/upload/abus”, “-1tr”, “|”, “head”, “-n”, “-3000”, “|”, “xargs”, “-d”, “\\n’”, “/bin/rm”, “-f”, “–”)

or you “simply” create a shell skript with the complete command inside. chmod, that the user openhab can execute the script. After that just call the script in the rule (only a example):

executeCommandLine(Duration.ofSeconds(10), “/app/scripts/skript.sh”)

Guys, you are quick!

I tried this already - does not work
(unfortunately the code above swallowed the second )

Alright - thank you.
I thought I could avoid shell scripts, but there is potentially no other way!

I’m struggling with this too. The problem is that the script I want to execute takes a variable number of arguments that are determined at runtime, so splitting them up like executeCommandLine("python", "/home/openhab/myscript.py", arg1, arg2, ...) is not an option. Replacing spaces with @ or @@ as often recommended doesn’t work either. Spaces were not a problem back in OH2’s executeCommandLine().

Why does this issue even exist? What is the purpose of splitting up arguments? Please just let me pass a string directly to bash or whatever like any other exec function out there does. That would also solve all problems that users have with piping etc at once.

Aren’t you missing the time out at the beginning?

executeCommandLine(Duration.ofSeconds(5), "python", "/home/openhab/myscript.py", "arg1", "arg2", "...")

Furthermore you need " around the args as well.

Encapsulate your call to python in a shell scirpt ( as long as you do not have dynamic arguments ).
Replacing spaces with @s does not work in OH3 afaik.

The timeout is optional. It’s just a little confusing (for me at least) because it comes first, and optional stuff usually comes at the tail end.

EDIT: Oops, we both missed this post from earlier in the conversation. So it’s required if you need a response, and not required if you don’t.

1 Like

That’s only required if you want to process the output.

I meant those to be variables. But this style of passing arguments isn’t useful for me anyway because I have a string with an arbitrary number of spaces.

That’s the problem.

That’s because of how Java’s Varargs work. If a method accepts an arbitrary number of arguments, they always need to be at the very end.

However, that’s also the solution! I just found out it’s possible to pass an array instead of individual arguments:

val cmnd = "python /home/openhab/myscript.py " + myarguments
executeCommandLine(cmnd.split(" "))

You can’t mix both however, so executeCommandLine("python", "/home/openhab/myscript.py", myarguments.split(" ")) will not work.

4 Likes