From d0cb804dfe41edd5752ec0634328fa22286a38fb Mon Sep 17 00:00:00 2001 From: lsiepel Date: Fri, 10 May 2024 19:54:56 +0200 Subject: [PATCH] [transformation][exec] allow spaces in parameters by enclosing in single quotes (#16160) Signed-off-by: Leo Siepel Signed-off-by: Ciprian Pascu --- bundles/org.openhab.transform.exec/README.md | 14 ++++++++------ .../exec/internal/ExecTransformationService.java | 7 +++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.transform.exec/README.md b/bundles/org.openhab.transform.exec/README.md index 7fdeceb370f..423b1d16fe8 100644 --- a/bundles/org.openhab.transform.exec/README.md +++ b/bundles/org.openhab.transform.exec/README.md @@ -5,6 +5,10 @@ Transforms an input string with an external program. Executes an external program and returns the output as a string. In the given command line the placeholder `%s` is substituted with the input value. +The provided command line is split on spaces before it is passed to the shell. +Using single quotes (`'`) splitting can be avoided (e.g. `'%s'` would prevent splitting on spaces within the input value). +The surrounding single quotes are removed. + The external program must either be in the executable search path of the server process, or an absolute path has to be used. For security reasons all commands need to be whitelisted. @@ -23,7 +27,7 @@ numfmt --to=iec-i --suffix=B --padding=7 %s ### General Setup -**Item** +#### Item This will replace the visible label in the UI with the transformation you apply with the command . @@ -31,7 +35,7 @@ This will replace the visible label in the UI with the transformation you apply String yourItem "Some info [EXEC(/absolute/path/to/your/ %s):%s]" ``` -**Rule** +#### Rule ```java rule "Your Rule Name" @@ -53,7 +57,7 @@ Substitute the `/absolute/path/to/your/` with When the input argument for `%s` is `fri` the execution returns a string with the last weekday of the month, formated as readable text. -``` +```shell Fri 31 Mar 2017 13:58:47 IST` ``` @@ -84,9 +88,7 @@ If omitted the default is `%s`, so the input value will be put into the transfor Please note: This profile is a one-way transformation, i.e. only values from a device towards the item are changed, the other direction is left untouched. -# Further Reading +## Further Reading * [Manual](http://man7.org/linux/man-pages/man1/date.1.html) and [tutorial](https://linode.com/docs/tools-reference/tools/use-the-date-command-in-linux/) for date. * [Manual](http://man7.org/linux/man-pages/man1/numfmt.1.html) and [tutorial](https://www.pixelbeat.org/docs/numfmt.html) for numfmt. - - diff --git a/bundles/org.openhab.transform.exec/src/main/java/org/openhab/transform/exec/internal/ExecTransformationService.java b/bundles/org.openhab.transform.exec/src/main/java/org/openhab/transform/exec/internal/ExecTransformationService.java index 4a743a6ac5d..5c56dff3137 100644 --- a/bundles/org.openhab.transform.exec/src/main/java/org/openhab/transform/exec/internal/ExecTransformationService.java +++ b/bundles/org.openhab.transform.exec/src/main/java/org/openhab/transform/exec/internal/ExecTransformationService.java @@ -13,6 +13,7 @@ package org.openhab.transform.exec.internal; import java.time.Duration; +import java.util.regex.Pattern; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -35,6 +36,7 @@ import org.slf4j.LoggerFactory; @NonNullByDefault @Component(property = { "openhab.transform=EXEC" }) public class ExecTransformationService implements TransformationService { + private static final Pattern SPLIT_ON_SPACE = Pattern.compile("(['])((?:\\\\\\1|.)+?)\\1|([^\\s']+)"); private final Logger logger = LoggerFactory.getLogger(ExecTransformationService.class); private final ExecTransformationWhitelistWatchService execTransformationWhitelistWatchService; @@ -66,8 +68,9 @@ public class ExecTransformationService implements TransformationService { long startTime = System.currentTimeMillis(); String formattedCommandLine = String.format(commandLine, source); - String result = ExecUtil.executeCommandLineAndWaitResponse(Duration.ofSeconds(5), - formattedCommandLine.split(" ")); + String[] cmdLineParts = SPLIT_ON_SPACE.matcher(formattedCommandLine).results() + .map(mr -> mr.group(2) == null ? mr.group() : mr.group(2)).toArray(String[]::new); + String result = ExecUtil.executeCommandLineAndWaitResponse(Duration.ofSeconds(5), cmdLineParts); logger.trace("command line execution elapsed {} ms", System.currentTimeMillis() - startTime); return result;