Repository: karaf Updated Branches: refs/heads/master 7cc5f5032 -> 7660ee68c
[KARAF-4273] Add -o (--only-matching) option to grep command [KARAF-4376] Make grep return the list of results rather than null Also refactor grep command using the gogo jline grep implementation which uses the AttributedString for ease of use. Project: http://git-wip-us.apache.org/repos/asf/karaf/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/7660ee68 Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/7660ee68 Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/7660ee68 Branch: refs/heads/master Commit: 7660ee68ca903f0531f6fb2ae902bb37c4754dd3 Parents: 7cc5f50 Author: Guillaume Nodet <[email protected]> Authored: Wed Sep 7 18:07:25 2016 +0200 Committer: Guillaume Nodet <[email protected]> Committed: Wed Sep 7 18:07:25 2016 +0200 ---------------------------------------------------------------------- .../karaf/shell/commands/impl/GrepAction.java | 211 ++++++++----- .../karaf/shell/commands/impl/LessAction.java | 2 +- .../karaf/shell/commands/impl/GrepTest.java | 294 +++++++++++++++++-- 3 files changed, 401 insertions(+), 106 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf/blob/7660ee68/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java ---------------------------------------------------------------------- diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java index 3d866f3..754a8b1 100644 --- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java +++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java @@ -18,21 +18,33 @@ */ package org.apache.karaf.shell.commands.impl; +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Argument; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.Completion; +import org.apache.karaf.shell.api.action.Option; +import org.apache.karaf.shell.api.action.lifecycle.Reference; +import org.apache.karaf.shell.api.action.lifecycle.Service; +import org.apache.karaf.shell.api.console.Session; +import org.apache.karaf.shell.support.completers.FileOrUriCompleter; +import org.jline.builtins.Source; +import org.jline.builtins.Source.StdInSource; +import org.jline.builtins.Source.URLSource; +import org.jline.terminal.Terminal; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; +import org.jline.utils.AttributedStyle; + import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStreamReader; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.karaf.shell.api.action.Action; -import org.apache.karaf.shell.api.action.Argument; -import org.apache.karaf.shell.api.action.Command; -import org.apache.karaf.shell.api.action.Option; -import org.apache.karaf.shell.api.action.lifecycle.Service; -import org.apache.karaf.shell.support.ansi.SimpleAnsi; - @Command(scope = "shell", name="grep", description="Prints lines matching the given pattern.", detailedDescription="classpath:grep.txt") @Service public class GrepAction implements Action { @@ -46,6 +58,10 @@ public class GrepAction implements Action { @Argument(index = 0, name = "pattern", description = "Regular expression", required = true, multiValued = false) private String regex; + @Argument(index = 1, multiValued = true) + @Completion(FileOrUriCompleter.class) + List<String> files; + @Option(name = "-n", aliases = { "--line-number" }, description = "Prefixes each line of output with the line number within its input file.", required = false, multiValued = false) private boolean lineNumber; @@ -81,6 +97,12 @@ public class GrepAction implements Action { @Option(name = "-C", aliases = { "--context" }, description = "Print NUM lines of output context. Places a line containing -- between contiguous groups of matches.", required = false, multiValued = false) private int context = 0; + @Option(name = "-o", aliases = { "--only-matching"}, description = "Print only the matching section of a line", required = false, multiValued = false) + private boolean onlyMatching; + + @Reference + Session session; + @Override public Object execute() throws Exception { if (after < 0) { @@ -89,11 +111,10 @@ public class GrepAction implements Action { if (before < 0) { before = context; } - List<String> lines = new ArrayList<String>(); String regexp = regex; if (wordRegexp) { - regexp = "\\b" + regexp + "\\b"; + regex = regexp = "\\b" + regexp + "\\b"; } if (lineRegexp) { regexp = "^" + regexp + "$"; @@ -109,99 +130,127 @@ public class GrepAction implements Action { p = Pattern.compile(regexp); p2 = Pattern.compile(regex); } - try { + + List<Source> sources = new ArrayList<>(); + if (files == null || files.isEmpty()) { + files = Collections.singletonList("-"); + } + Path pwd = Paths.get(System.getProperty("karaf.home", System.getProperty("user.dir"))); + for (String arg : files) { + if ("-".equals(arg)) { + sources.add(new StdInSource()); + } else { + sources.add(new URLSource(pwd.toUri().resolve(arg).toURL(), arg)); + } + } + + Terminal terminal = session != null ? (Terminal) session.get(".jline.terminal") : null; + List<Object> output = new ArrayList<>(); + for (Source source : sources) { boolean firstPrint = true; int nb = 0; int lineno = 1; String line; int lineMatch = 0; - BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); - while ((line = r.readLine()) != null) { - if (line.length() == 1 && line.charAt(0) == '\n') { - break; - } - if (p.matcher(line).matches() ^ invertMatch) { - Matcher matcher2 = p2.matcher(line); - StringBuffer sb = new StringBuffer(); - while (matcher2.find()) { + List<String> lines = new ArrayList<>(); + try (BufferedReader r = new BufferedReader(new InputStreamReader(source.read()))) { + while ((line = r.readLine()) != null) { + if (line.length() == 1 && line.charAt(0) == '\n') { + break; + } + if (p.matcher(line).matches() ^ invertMatch) { + AttributedStringBuilder sbl = new AttributedStringBuilder(); + if (color != ColorOption.never) { + sbl.style(getSourceStyle()); + } + if (!count && sources.size() > 1) { + sbl.append(source.getName()); + sbl.append(":"); + } + if (!count && lineNumber) { + sbl.append(String.format("%6d ", lineno)); + } + sbl.style(AttributedStyle.DEFAULT); + Matcher matcher2 = p2.matcher(line); + AttributedString aLine = AttributedString.fromAnsi(line); + AttributedStyle style; if (!invertMatch && color != ColorOption.never) { - int index = matcher2.start(0); - String prefix = line.substring(0,index); - matcher2.appendReplacement(sb, - "\u001b[33;40m" + matcher2.group() + "\u001b[39;49m" + lastEscapeSequence(prefix)); + style = getMatchingStyle(); } else { - matcher2.appendReplacement(sb, matcher2.group()); + style = AttributedStyle.DEFAULT; } - nb++; - } - matcher2.appendTail(sb); - if(color != ColorOption.never) { - sb.append(SimpleAnsi.RESET); - } - if (!count && lineNumber) { - lines.add(String.format("%6d ", lineno) + sb.toString()); + if (invertMatch) { + nb++; + sbl.append(aLine); + } else if (onlyMatching) { + while (matcher2.find()) { + int index = matcher2.start(0); + int cur = matcher2.end(); + sbl.append(aLine.subSequence(index, cur), style); + nb++; + } + } else { + int cur = 0; + while (matcher2.find()) { + int index = matcher2.start(0); + AttributedString prefix = aLine.subSequence(cur, index); + sbl.append(prefix); + cur = matcher2.end(); + sbl.append(aLine.subSequence(index, cur), style); + nb++; + } + sbl.append(aLine.subSequence(cur, aLine.length())); + } + lines.add(sbl.toAnsi(terminal)); + lineMatch = lines.size(); } else { - lines.add(sb.toString()); - } - lineMatch = lines.size(); - } else { - if (lineMatch != 0 & lineMatch + after + before <= lines.size()) { - if (!count) { - if (!firstPrint && before + after > 0) { - System.out.println("--"); - } else { - firstPrint = false; + if (lineMatch != 0 & lineMatch + after + before <= lines.size()) { + if (!count) { + if (!firstPrint && before + after > 0) { + output.add("--"); + } else { + firstPrint = false; + } + for (int i = 0; i < lineMatch + after; i++) { + output.add(lines.get(i)); + } } - for (int i = 0; i < lineMatch + after; i++) { - System.out.println(lines.get(i)); + while (lines.size() > before) { + lines.remove(0); } + lineMatch = 0; } - while (lines.size() > before) { + lines.add(line); + while (lineMatch == 0 && lines.size() > before) { lines.remove(0); } - lineMatch = 0; - } - lines.add(line); - while (lineMatch == 0 && lines.size() > before) { - lines.remove(0); } + lineno++; } - lineno++; - } - if (!count && lineMatch > 0) { - if (!firstPrint && before + after > 0) { - System.out.println("--"); - } else { - firstPrint = false; + if (!count && lineMatch > 0) { + if (!firstPrint && before + after > 0) { + output.add("--"); + } else { + firstPrint = false; + } + for (int i = 0; i < lineMatch + after && i < lines.size(); i++) { + output.add(lines.get(i)); + } } - for (int i = 0; i < lineMatch + after && i < lines.size(); i++) { - System.out.println(lines.get(i)); + if (count) { + output.add(nb); } } - if (count) { - System.out.println(nb); - } - } catch (IOException e) { } - return null; + return output; } + private AttributedStyle getSourceStyle() { + return AttributedStyle.DEFAULT.foreground(AttributedStyle.BLACK + AttributedStyle.BRIGHT); + } - /** - * Returns the last escape pattern found inside the String. - * This method is used to restore the formating after highliting the grep pattern. - * If no pattern is found just returns the reset String. - * @param str - * @return - */ - private String lastEscapeSequence(String str) { - String escapeSequence = SimpleAnsi.RESET; - String escapePattern = "(\\\u001B\\[[0-9;]*[0-9]+m)+"; - Pattern pattern = Pattern.compile(escapePattern); - Matcher matcher = pattern.matcher(str); - while(matcher.find()) { - escapeSequence = matcher.group(); - } - return escapeSequence; + private AttributedStyle getMatchingStyle() { + return AttributedStyle.DEFAULT.bold().foreground(AttributedStyle.RED); } + } http://git-wip-us.apache.org/repos/asf/karaf/blob/7660ee68/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LessAction.java ---------------------------------------------------------------------- diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LessAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LessAction.java index 6d972f6..0479ba8 100644 --- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LessAction.java +++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LessAction.java @@ -89,7 +89,7 @@ public class LessAction implements Action { if (files == null || files.isEmpty()) { files = Collections.singletonList("-"); } - Path pwd = Paths.get(System.getProperty("karaf.home")); + Path pwd = Paths.get(System.getProperty("karaf.home", System.getProperty("user.dir"))); for (String arg : files) { if ("-".equals(arg)) { sources.add(new StdInSource()); http://git-wip-us.apache.org/repos/asf/karaf/blob/7660ee68/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java ---------------------------------------------------------------------- diff --git a/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java b/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java index 10dbe51..b96d1da 100644 --- a/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java +++ b/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java @@ -18,49 +18,295 @@ */ package org.apache.karaf.shell.commands.impl; +import org.apache.karaf.shell.impl.action.command.DefaultActionPreparator; +import org.junit.Test; + import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.PrintStream; import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; -import junit.framework.TestCase; -import org.apache.karaf.shell.impl.action.command.DefaultActionPreparator; +import static org.junit.Assert.*; + +public class GrepTest { -public class GrepTest extends TestCase { + private static final String ANSI_COLOR = "\u001b[1;31m"; + private static final String ANSI_RESET = "\u001b[0m"; + @Test public void testGrep() throws Exception { - InputStream input = System.in; - try { - ByteArrayInputStream bais = new ByteArrayInputStream("1\n2\n3\n4\n5\n6\n7\n8\n9\n".getBytes()); - System.setIn(bais); + final String expectedColoredString = "1\n" + ANSI_COLOR + "2" + + ANSI_RESET + "\n" + + "3\n4\n5\n6\n7\n8\n9"; - GrepAction grep = new GrepAction(); - DefaultActionPreparator preparator = new DefaultActionPreparator(); - preparator.prepare(grep, null, Arrays.<Object>asList("-C", "100", "2")); - grep.execute(); - } finally { - System.setIn(input); - } + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-C", "100", "2")); + final String returnedString = systemInOutDecorator("1\n2\n3\n4\n5\n6\n7\n8\n9\n", grep); + assertEquals(expectedColoredString, returnedString); + } + + @Test + public void testGrepInverted() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-v", "--color", "never", "mine")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals("This is Hello World\nHello World!", returnedString); + } + + @Test + public void testGrepMatching() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("--color", "never", "mine")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals("World is mine", returnedString); } + @Test + public void testGrepMatchingWithColours() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("--color", "always", "mine")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals("World is " + ANSI_COLOR + "mine" + ANSI_RESET, returnedString); + } + + @Test + public void testGrepCount() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-c", "Hello World")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals("2", returnedString); + } + + @Test + public void testGrepCountInvert() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-c", "-v", "Hello World")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals("1", returnedString); + } + + @Test + public void testGrepInvertedWithLineNumbers() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-n", "-v", "--color", "never", "mine")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(" 1 This is Hello World\n 3 Hello World!", returnedString); + } + + @Test + public void testGrepMatchingWithLineNumbers() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-n", "--color", "never", "Hello")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(" 1 This is Hello World\n 3 Hello World!", returnedString); + } + + @Test + public void testGrepWordRegExp() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-w", "--color", "never", "is")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals("This is Hello World\nWorld is mine", returnedString); + } + + @Test + public void testGrepIs() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("--color", "never", "is")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals("This is Hello World\nWorld is mine", returnedString); + } + + @Test + public void testGrepRegExpWithColour() throws Exception { + GrepAction grep = new GrepAction(); + final String expected = "Th" + + ANSI_COLOR + + "is" + ANSI_RESET + + " " + + ANSI_COLOR + + "is" + ANSI_RESET + + " Hello World\nWorld " + + ANSI_COLOR + + "is" + ANSI_RESET + + " mine"; + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("--color", "always", "is")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(expected, returnedString); + } + + @Test + public void testGrepWordRegExpWithColour() throws Exception { + GrepAction grep = new GrepAction(); + final String expected = "This " + + ANSI_COLOR + + "is" + ANSI_RESET + + " Hello World\nWorld " + + ANSI_COLOR + + "is" + ANSI_RESET + + " mine"; + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-w", "--color", "always", "is")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(expected, returnedString); + } + + @Test + public void testGrepLineRegExpWithColour() throws Exception { + GrepAction grep = new GrepAction(); + final String expected = ANSI_COLOR + + "This is Hello World" + ANSI_RESET; + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-x", "--color", "always", ".*Hello World")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(expected, returnedString); + } + + @Test + public void testGrepTwoLinesRegExpWithColour() throws Exception { + GrepAction grep = new GrepAction(); + final String expected = ANSI_COLOR + + "This is Hello World" + ANSI_RESET + "\n" + + ANSI_COLOR + + "Hello World!" + ANSI_RESET; + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-x", "--color", "always", ".*Hello World.*")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(expected, returnedString); + } + + @Test + public void testGrepIgnoreCaseWithColour() throws Exception { + GrepAction grep = new GrepAction(); + final String expected = "This is " + + ANSI_COLOR + + "hello" + ANSI_RESET + " World\n" + + ANSI_COLOR + + "Hello" + ANSI_RESET + " World!"; + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-i", "--color", "always", "HELLO")); + final String returnedString = systemInOutDecorator("This is hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(expected, returnedString); + } + + @Test + public void testGrepContextOneWithColour() throws Exception { + GrepAction grep = new GrepAction(); + final String expected = "This is " + + ANSI_COLOR + + "Hello" + ANSI_RESET + " World\n" + + "World is mine\n" + + ANSI_COLOR + + "Hello" + ANSI_RESET + " World!"; + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-C", "1", "--color", "always", "Hello")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(expected, returnedString); + } + + @Test + public void testGrepBeforeContextOneWithColour() throws Exception { + GrepAction grep = new GrepAction(); + final String expected = "World is mine\n" + + ANSI_COLOR + + "Hello World!" + ANSI_RESET; + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-B", "1", "--color", "always", "Hello World!")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(expected, returnedString); + } + + @Test + public void testGrepAfterContextOneWithColour() throws Exception { + GrepAction grep = new GrepAction(); + final String expected = "World is " + + ANSI_COLOR + + "mine" + ANSI_RESET + + "\nHello World!"; + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-A", "1", "--color", "always", "mine")); + final String returnedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals(expected, returnedString); + } + + @Test + public void testGrepOnlyMatching() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-o", "--color", "never", "He.*rld")); + final String expectedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals("Hello World\nHello World", expectedString); + } + + @Test + public void testGrepOnlyMatchingGroup() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("-o", "--color", "never", "(This).*(Hello)")); + final String expectedString = systemInOutDecorator("This is Hello World\nWorld is mine\nHello World!\n", + grep); + assertEquals("This is Hello", expectedString); + } + + @Test public void testHonorColorNever() throws Exception { + GrepAction grep = new GrepAction(); + DefaultActionPreparator preparator = new DefaultActionPreparator(); + preparator.prepare(grep, null, Arrays.asList("--color", "never", "b")); + final String expectedString = systemInOutDecorator("abc\n", + grep); + assertEquals("abc", expectedString); + + } + + private String systemInOutDecorator(String inputString, GrepAction grepExecute) throws Exception { InputStream input = System.in; PrintStream output = System.out; try { - ByteArrayInputStream bais = new ByteArrayInputStream("abc".getBytes()); + ByteArrayInputStream bais = new ByteArrayInputStream(inputString.getBytes()); System.setIn(bais); - ByteArrayOutputStream outContent = new ByteArrayOutputStream(); - System.setOut(new PrintStream(outContent)); - - GrepAction grep = new GrepAction(); - DefaultActionPreparator preparator = new DefaultActionPreparator(); - preparator.prepare(grep, null, Arrays.<Object>asList( "--color", "never", "b")); - grep.execute(); - assertEquals("abc", outContent.toString().trim()); + + String result = ((List<Object>) grepExecute.execute()).stream() + .map(Object::toString).collect(Collectors.joining("\n")); + if (result.length() > 1 && result.charAt(result.length() - 1) == '\n') { + result = result.substring(0, result.length() - 1); + } + return result; } finally { System.setIn(input); System.setOut(output); } } + }
