Getting any word and last word using sed - java

I'm working with the bash shell and now need some back up with a search.
I have a one line java configuration output in which I got two information which I need. These outputs are extremely long and confusing, so I wanted to use sed to clear it up.
So, I tried this:
sed -n 's/(.[a-z]*[0-9]*[a-z])/*\([^ ]* *\)/\1 \2/'
What I need from the file is Xmx which is build up like this: Xmx1024m
I also need the last word of this line.
Example:
was.status.socket=58963 -Dosgi.install.area.configuration.area=opt/was/example -Xms256m -Xmx1024m -Xcompressedrefs -Djavarofiles/nodeagent/properties/server.policy lastword
What I need:
Xmx1024 lastword
Can you help me out?
Thanks!
KevinD

The following removes everything before Xmx and everything after it up to the last word:
sed 's/.*\(Xmx[^ ]*\) .* /\1 /'

sed -r 's/.*(Xmx[0-9]+)m.* /\1 /'
Example:
sdlcb#ubuntu:~/AMD_C$ echo "was.status.socket=58963 -Dosgi.install.area.configuration.area=opt/was/example -Xms256m -Xmx1024m -Xcompressedrefs -Djavarofiles/nodeagent/properties/server.policy lastword" | sed -r 's/.*(Xmx[0-9]+)m.* /\1 /'
Xmx1024 lastword

Related

Java Runtime.exec() works for some command but not others [duplicate]

This question already has an answer here:
Why does Runtime.exec(String) work for some but not all commands?
(1 answer)
Closed 10 months ago.
I am doing an exercise related to Runtime.exec(), I understand that Runtime.exec is not a shell interpreter, that's why I execute "bash -c 'command'" instead, but for some reason, I can execute commands like ls bash -c 'ls' but not echo or redirection or multiple commands. These does not work:
bash -c 'echo 1234'
bash -c 'ls > abc'
bash -c 'ls;id'
bash -c 'ls -al'
Here is my java code:
import java.util.*;
import java.io.*;
public class runtime {
public static void main(String args[]) throws Exception{
String cmd = args[0];
System.out.println(cmd);
Process p = Runtime.getRuntime().exec(cmd);
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
DataInputStream dis = new DataInputStream(in);
String disr = dis.readLine();
while ( disr != null ) {
System.out.println("Out: " + disr);
disr = dis.readLine();
}
}
}
I run the above commands with the syntax:
java runtime "bash -c 'command'"
This works:
$ java runtime "bash -c 'ls'"
bash -c 'ls'
Out: Main.class
Out: Main.java
Out: runtime.class
Out: runtime.java
I am using openjdk 11.0.15 on Ubuntu 20.04 and zsh.
Can anyone tell me why Runtime doesn't work in this case? Thank you!
Because of shell parsing.
These are all concepts that the OS just does not have:
The concept of 'every space separates one argument from another (and the command from the list of arguments'). The concept that a single string can possibly run anything, in fact; at the OS level that's just not what the 'run this thing' API looks like. When you type commands on the command prompt, your shell app is 'interpreting' these strings into a command execution request.
The concept of figuring out that bash means /bin/bash, i.e. $PATH resolution.
The concept that *.txt is supposed to refer to all files that ends in .txt.
The concept that $FOO should be replaced with the value of the environment variable 'FOO'
The concept that ; separates 2 commands, and it's supposed to run both.
The concept that single and double quotes escape things. "Escape things" implies that things can cause interpretation to happen. The OS interprets nothing, therefore there's nothing to escape. Obvious, then, that the OS doesn't know what ' is, or ".
That >foo means: Please set the standard output of the spawned process such that it sends it all to file 'foo'.
In windows shells, that # in front of the command means 'do not echo the command itself'. This and many other things are shellisms: /bin/bash does that, maybe /bin/zsh does something else. Windows's built in shell thing definitely is quite different from bash!
Instead, an OS simply wants you to provide it a full path to an executable along with a list of strings, and pick targets for standard in, standard out, and standard err. It does no processing on any of that, just starts the process you named, and passes it the strings verbatim.
You're sort of half there, as you already figured out that e.g. ls >foo cannot work if you execute it on its own, but it can work if you tell bash to execute it. As ALL of that stuff in the above list? Your shell does that.
It gets more complicated: Turning *.txt into foo.txt bar.txt is a task of bash and friends, e.g. if you attempted to run: ls '*.txt' it does not work. But on windows, it's not the shell's job; the shell just passes it verbatim to dir, and it is the command's job to undo it. What a mess, right? Executing things is hard!
So, what's wrong here? Two things:
Space splitting isn't working out.
Quote application isn't being done.
When you write:
bash -c 'ls >foo'
in a bash shell, bash has to first split this up, into a command, and a list of arguments. Bash does so as follows:
Command: bash
arg1: -c
arg2: ls >foo
It knows that ls >foo isn't 2 arguments because, effectively, "space" is the bash operator for: "... and here is the next argument", and with quotes (either single or double), the space becomes a literal space instead of the '... move to next argument ...' operator.
In your code, you ask bash to run java, and then java to run bash. So, bash first does:
cmd: java
arg1: bash -c 'ls >foo'
With the same logic at work. Your java app then takes that entire string (that's args[0]: "bash -c 'ls >foo'"), and you then feed it to a method you should never use: Runtime.exec(). Always use ProcessBuilder, and always use the list-based form of it.
Given that you're using the bad method, you're now asking java to do this splitting thing. After all, if you just tell the OS verbatim, please run "bash -c 'ls >foo'", the OS dutifully reports: "I'm sorry, but file ./bash -c ;ls >foo' does not exist", because it does not processing at all". This is unwieldy so java's exec() method is a disaster you should never use: Because people are confused about this, it tries to do some extremely basic processing, except every OS and shell is different, java does not know this, so it does a really bad job at it.
Hence, do not use it.
In this case, java doesn't realize that those quotes mean it shouldn't split, so java tells the OS:
Please run:
cmd: /bin/bash (java DOES do path lookup; but you should avoid this, do not use relative path names, you should always write them out in full)
arg1: -c
arg2: 'ls
arg3: >foo'
and now you understand why this is just going completely wrong.
Instead, you want java to tell the OS:
cmd: /bin/bash
arg1: -c
arg2: ls >foo
Note: ls >foo needs to be one argument, and NOTHING in the argument should be containing quotes, anywhere. The reason you write:
/bin/bash -c 'ls >foo'
In bash, is because you [A] want bash not to treat that space between ls and >foo as an arg separator (you want ls >foo to travel to /bin/bash as one argument), and [B] that you want >foo to just be sent to the bash you're spawning and not to be treated as 'please redirect the output to file foo' at the current shell level.
Runtime.exec isn't a shell, so the quotes stuff? Runtime.exec has no idea.
This means more generally your plan of "I shall write an app where the entire argument you pass to it is just run" is oversimplified and can never work unless you write an entire quotes and escaper analyser for it.
An easy way out is to take the input, write it out to a shell script on disk, set the exec flag on it, and always run /bin/bash -c /path/to/script-you-just-wrote, sidestepping any need to attempt to parse anything in java: Let bash do it.
The ONE weird bizarro thing I cannot explain, is that literally passing 'ls' to /bin/bash -c, with quotes intact, DOES work and runs ls as normal, but 'ls *' does not, perhaps because now bash thinks you want executable file /bin/ls * which obviously does not exist (a star cannot be in a file name, or at least, that's not the ls executable, and it's not an alias for the ls built-in). At any rate, you want to pass ls without the quotes.
Let's try it!
import java.util.*;
import java.io.*;
public class runtime {
public static void main(String args[]) throws Exception{
ProcessBuilder pb = new ProcessBuilder();
pb.command("/bin/bash", "-c", "echo 1234");
// pb.command("/bin/bash", "-c", "'echo 1234'");
Process p = pb.start();
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
DataInputStream dis = new DataInputStream(in);
String disr = dis.readLine();
while ( disr != null ) {
System.out.println("Out: " + disr);
disr = dis.readLine();
}
int errCode = p.waitFor();
System.out.println("Process exit code: " + errCode);
}
}
The above works fine. Replace the .command line with the commented out variant and you'll notice it does not work at all, and you get an error. On my mac I get a '127' error; perhaps this is bash reporting back: I could not find the command you were attempting to execute. 0 is what you're looking for when you invoke waitFor: That's the code for 'no errors'.

Want to read Code from Windows Command Skipt(CMD) File and extract Information

a specific directory receives some different files including some .cmd files.
Here is and example of one of these:
X_COMMAND=DELETE_DOCUMENT
X_DOCIDENTIFICATION=FREE
DTY=MSDS
X_DELIMITER=;
X_FollowingFields=STA;DTY;PRN;SID;CTY;LAN;VKG
V;MSDS;340000021613012300;800000000160;ES;E;ES00
I want to work with the last 2 lines of Code to extract Data:
String xyz = (the command to get 340000021613012300);
The Question is: How do I get this Data?
I have tried to look this up, but did not find anything regarding this issue. If you can help me with this or redirect me to the information I look for I would appreciate that.
Thank you for your time helping me here.
Here is one way to do it. If you are on a supported Windows system, PowerShell will be available.
FOR /F %%A IN ('powershell -NoLogo -NoProfile -Command ^
"(Get-Content -Path "C:\src\t\Get-LastLineData.txt" |" ^
"Select-Object -Last 1).Split(';')[2]"') DO (
SET "xyz=%%~A"
)
ECHO %xyz%
If your script could be written in PowerShell, it would just be:
$xyz = (Get-Content -Path "C:\src\t\Get-LastLineData.txt" |
Select-Object -Last 1).Split(';')[2]
Using just cmd:
for /f "tokens=3 delims=;" %%a in (file.ext) do set "xyz=%%a"
echo %xyz%
(assuming you want the third token of the last line)

How to properly pass git ls-files output to Java, if there is any file name with white spaces?

I'm trying to handle the output of git ls-files in a Java program. Usage is simple:
java Test $(git ls-files)
Test.java:
public class Test {
public static void main(String[] args) {
for (String s : args) {
System.out.println(s);
}
}
}
which simply prints out all arguments for now.
Output of git ls-files:
input $.csv
input_1.csv
input_2.csv
input_3.csv
Note that the first one, input $.csv, has a space in the middle.
My desired output is of course:
input $.csv
input_1.csv
input_2.csv
input_3.csv
However, what Test prints out is:
input
$.csv
input_1.csv
input_2.csv
input_3.csv
The space actually breaks my expectation.
Therefore I tried to sed to wrap all file names in quotes:
java Test $(git ls-files | sed "s/\(.*\)/'\1'/g")
The output of $(git ls-files | sed "s/\(.*\)/'\1'/g") is as expected:
'input $.csv'
'input_1.csv'
'input_2.csv'
'input_3.csv'
However, Test still prints out the same output with and without sed. What could be wrong with my scripts?
To preserve special characters in the output of git ls-files, use the -z flag.
To pass the null-delimited output of git ls-files -z as a list of command line arguments, store the output first in a temporary Bash array, using the mapfile builtin (requires at least Bash 4).
Then you can pass the array on the command line,
correctly preserving special characters.
mapfile -d '' files < <(git ls-files -z)
java Test "${files[#]}"

Not printing anything after for loop in a batch script

Below is my batch script which is not executing the line after for loop end. It's not print echo end or the line after that. The line asciidoctor-pdf C:\Users\abc\Conversion_to_PDF\OutputFiles\*.adoc is causing it. But I am not sure with what the problem is.
#echo off
echo # Starting job
java -jar C:\Users\abc\Conversion_to_PDF\swagger2markup-cli-1.3.1.jar convert -i C:\Users\abc\Conversion_to_PDF\HIP-ProviderManagement-1.0.0-swagger.json -d C:\Users\abc\Conversion_to_PDF\OutputFiles
chdir /d C:\Users\abc\Conversion_to_PDF\OutputFiles
for %%A in (*.adoc) do (
asciidoctor-pdf C:\Users\abc\Conversion_to_PDF\OutputFiles\*.adoc
echo %%A
)
echo # end
C:\Users\abc\Downloads\sejda-console-3.2.3\bin\sejda-console merge -f C:\Users\abc\Conversion_to_PDF\OutputFiles\*.pdf -o C:\Users\abc\Conversion_to_PDF\OutputFiles\merged.pdf
You need
call asciidoctor-pdf ....
since asciidoctor-pdf is a batch file. The call means "execute this, then return to the next statement". Without the call, it means "go to this batchfile" and it is not told to return to the original (the "caller")

change a line using 'sed" command for Java/Android

I am trying to change a line using 'sed" command for Android. I have used the following commands but it is not working. Noted here, my file location is in "root" folder at Android device. I also want to change the value from 20 to 10.
String[] cmd = { "su", "#!/bin/bash\n",
"sed -i 's/p2p_oper_channel/replacing_text/g' data/misc/wifi/p2p_supplicant.conf" };
Process p = Runtime.getRuntime().exec(cmd);
Can anone help me about this issue?
Using the sed command like that will only execute the substitution but it will output to stdout. You probably want to apply the substitution to the original file. To achieve that you need to supply an option to sed, the -i option for inline change.
Your command should therefor look like this:
sed -i 's/pattern_text=20/text_to_replace=10/g' /data/location/to/file.txt
Edit
In light if your most recent details, here's a command that ought to work:
sed -i 's/\(p2p_oper_channel=\)[0-9]\+/\1x/' /data/misc/wifi/p2p_supplicant.conf
Note that the part \1 means insert the part between the \( and \), i.e. the string p2p_oper_channel and the x will insert an x. Change the x to the number you want to insert instead of the current one.
This is the most flexible way, now let's take the most static one.
sed -i 's/p2p_oper_channel=[0-9]\+/p2p_oper_channel=x/' /data/misc/wifi/p2p_supplicant.conf
Where you, again, replace x with the desired value.
Edit2
Thanks to Wintermute's input, we found out escape symbols need to be escaped in Java. Reuslting in a new sed function:
sed -i 's/p2p_oper_channel=[0-9]\\+/p2p_oper_channel=x/' /data/misc/wifi/p2p_supplicant.conf

Categories

Resources