Running pipelined commands using ProcessBuilder in Java - java

I am trying to extract the frequency of the most frequent line in a file using the following command:
sort file.txt | uniq -c | sort -r | head -1| xargs
I am trying to accomplish from within a Java program, using the ProcessBuilder class. Here is how I am passing to its constructor:
ProcessBuilder builder=new ProcessBuilder("/bin/sh", "-c","sort",fileName,"| uniq -c | sort -r | head -1 | xargs");
When I run the program, it just stops executing beyond this line. There are no errors, but the program just halts at this line. What is it that I might be doing wrong?
Thanks!

Try including a filename directly into command:
ProcessBuilder builder=new ProcessBuilder("/bin/sh", "-c","sort " + fileName + " | uniq -c | sort -r | head -1 | xargs");

Related

Bash command not working with ProcessBuilder

The following command executes fine in bash:
Command:
bash -c "$(echo 'H4sIAArQ/mAAA1WMuw7CIBRAd77ihLJqtKuTg19hHIjetiQU0svl/1sn43weaeKJD4PnlI2R1w1bpOBA3kvF340ssX1Z1LmvUqyhsvWk8jl7nOQmP/2x9ZixSlXWqnLcYvlrw4VwJYxHOiW3AwCHgS2AAAAA' | base64 --decode | zcat)" - -a -b
Output:
Equal to or more than 2 arguments - -a -b
Wanted to know - how can I achieve this using Java's ProcessBuilder?
I tried the following:
ProcessBuilder processBuilder = new ProcessBuilder(args);
where args are:
bash
-c
"$(echo 'H4sIAArQ/mAAA1WMuw7CIBRAd77ihLJqtKuTg19hHIjetiQU0svl/1sn43weaeKJD4PnlI2R1w1bpOBA3kvF340ssX1Z1LmvUqyhsvWk8jl7nOQmP/2x9ZixSlXWqnLcYvlrw4VwJYxHOiW3AwCHgS2AAAAA' | base64 --decode | zcat)"
-
-a
-b
But I keep on getting the following error:
-: if: command not found
Process finished with exit code 127
Can someone please point out the issue here?
Command substitution results, in bash, don't go through all parsing steps. That means that compound commands like if aren't honored, command separators like ; have no syntactic meaning, etc.
If you want to override that and force an additional parsing pass, you need to use eval. Thus:
args = String[]{
"bash",
"-c",
"eval \"$(echo 'H4sIAArQ/mAAA1WMuw7CIBRAd77ihLJqtKuTg19hHIjetiQU0svl/1sn43weaeKJD4PnlI2R1w1bpOBA3kvF340ssX1Z1LmvUqyhsvWk8jl7nOQmP/2x9ZixSlXWqnLcYvlrw4VwJYxHOiW3AwCHgS2AAAAA' | base64 --decode | zcat)\"",
"-",
"-a",
"-b",
}
Why did this work when you ran it in a shell, instead of from a ProcessBuilder? Because that shell you ran it in would perform the command substitution in "$(...)", and put the results of that substitution in the text it passed to the child shell; so the substitution was already done at parsing time.

String concatenating error in shell script executing

This is a wired problem confusing me for days.I want to get a class's full class name from parse the java code file in shell.We can get package name from like:
package com.android.mail.ui;
and get class name from code file path,use shell command 'basename'.
below is my shell scripts:
#!/bin/bash
get_package_name(){
java_file=$1
if [ ! -f $file_path ]; then
echo "Sorry,the java file is not exist:$1,please check"
exit 1
fi
class_base_name=`basename "$java_file" .java`
echo "class_base_name:$class_base_name"
package_name=`grep $java_file -e "^package" | awk -F " " '{print $2}' | tr ';' ' ' | sed 's/ //g'`
echo "package_name get result:$?"
echo "package_name:$package_name"
method 1,use variable concat directly
classpath_name=$package_name.$class_base_name
echo "method 1 classpath_name:$classpath_name"
method 2,use sed replace to get concat indirectly
classpath_name2=`echo "aa.bb" | sed "s/aa/$package_name/" | sed "s/bb/$class_base_name/"`
echo "method 2 classpath_name2:$classpath_name2"
}
The problem is:for some code file the result is ok,like:
"class_base_name:MailTransport package_name get result:0
package_name:com.android.email.mail.transport method 1
classpath_name:com.android.email.mail.transport.MailTransport method 2
classpath_name2:com.android.email.mail.transport.MailTransport"
for others it's output is : "class_base_name:EmailApplication
package_name get result:0 package_name:com.android.email
.EmailApplicationh_name:com.android.email
.EmailApplicationh_name2:com.android.email"
the result is totally messing and wrong.I doubt it relates the code
content,that really make sense for the result?
This happens because some of your files use Windows style CRLF (\r\n) line terminators.
Here's an example where it works, a normal Unix style LF (\n) terminated file:
$ file WorkingFile.java
WorkingFile.java: ASCII text
$ cat -v WorkingFile.java
package foo.bar.baz;
$ get_package_name WorkingFile.java
class_base_name:WorkingFile
package_name get result:0
package_name:foo.bar.baz
method 1 classpath_name:foo.bar.baz.WorkingFile
Here's an example where it fails, with CRLF line terminators:
$ file FailingFile.java
FailingFile.java: ASCII text, with CRLF line terminators
$ cat -v FailingFile.java
package foo.bar.baz;^M <--- note hidden control char revealed by -v
$ get_package_name FailingFile.java
class_base_name:FailingFile
package_name get result:0
package_name:foo.bar.baz
.FailingFilesspath_name:foo.bar.baz
To fix it, you can delete the extra carriage returns using tr -d '\r'. I switched from legacy backticks to modern $() to avoid problems with backslashes:
package_name=$(grep $java_file -e "^package" | awk -F " " '{print $2}' | tr ';' ' ' | sed 's/ //g' | tr -d '\r')
For more information, see this relevant post.

Grep for the 5 lines after a specific text string found in files

I have many java files, and I want to find how many times we are logging via
logger.isDebugEnabled(){
logger.Debug("some debug message");
}
To get an idea of how often we may be overusing the isDebugEnabled function. I have found the number of times we have called/where it is called via
grep -r "isDebugEnabled" --include=*.java . | wc -l
But I want to know how many of those are 1 line statements. Does anyone have a good script to search for this or any ideas on the most efficient way of doing this?
Don’t use grep for this, use the following AWK program:
prev ~ /isDebugEnabled/ && $0 ~ /logger\.Debug\("[^"]"\)/ {
print FILENAME ":" NR ": " $0
}
{
prev = $0
}
This program remembers the previous line in the prev variable and thereby allows you to compare two lines at a time.
To actually use it, write:
find . -name '*.java' -print \
| xargs awk 'prev ~ /isDebugEnabled/ && /logger\.Debug\("[^"]"\)/ { print FILENAME ":" NR ": " $0 } { prev = $0 }'
As mentioned in comments grep provides options to print certain number of lines after and before match.
To print lines after match:
grep -A 2 "string to match" file.txt
To print lines before match:
grep -B 2 "string to match" file.txt
Before you try to write a script giving one final answer, try different approaches for insight what is best for what you want. Test with one file.
Do you think, that logger.Debug("The database has ", getDbNum(), "and the server has ", getRemoteNumSpecial(), "records."); is a simple oneliner?
You can collect some numbers for a first orientation. The examples beneath is using x.java as example sourcefile.
# Nr of isDebugEnabled calls
grep -c "logger.isDebugEnabled" x.java
# Some may be comment with //
grep -c "//.*logger.isDebugEnabled" x.java
# How much debug-lines
grep -c "logger.Debug" x.java
# How much debug-lines with more than 1 parameter (having a ,)
grep -c "logger.Debug.*," x.java
# How much debug-lines without the closing ) on the same line
grep "logger.Debug" x.java | grep -v "Debug.*)"
# How much logger.isDebugEnabled() without a logger.Debug on the next line
grep -A1 "logger.isDebugEnabled" x.java | grep -c "logger.Debug"
# How much logger.Debug a "}" on the next line
# The debugline might have a }, so skip lines with logger.Debug
grep -A1 "logger.Debug" x.java | grep -v "logger.Debug" | grep -c "}"

Piped unix command not executing in java Program

I am trying to get the memory usage for a particular Process using its pid in a java program
using the following command
ps -eo pid,pmem,comm | grep java | awk '{print ($2)}'
While this command works on unix terminal, it does not work in java I keep on getting null result even when I run another java program (to populate the ps table with java processes).
String[] PipedCommand = {
"/bin/bash",
"-c",
"ps -eo pid,pmem,comm | grep java | awk '{print ($2)}'"
};
Process command1=Runtime.getRuntime().exec(PipedCommand);
command1.waitFor();
BufferedReader reader1=new BufferedReader(new InputStreamReader(command.getInputStream()));
String line1=reader1.readLine();
if(line1 != null)
{
System.out.println(" Memory percentage is "+line1);
}
I would appreciate if someone could tell me if there is something wrong with the approach

How to generate a call graph for a java project

Is it possible to generate a global call graph of an application?
Basically I am trying to find the most important class of an application.
I am looking for options for Java.
I have tried Doxy Gen, but it only generates inheritance graphs.
My current script:
#! /bin/bash
echo "digraph G
{"
find $1 -name \*.class |
sed s/\\.class$// |
while read x
do
javap -v $x | grep " = class" | sed "s%.*// *%\"$x\" -> %" | sed "s/$1\///" | sed "s/-> \(.*\)$/-> \"\1\"/"
done
echo "}"
javap -v and a bit of perl will get you dependencies between classes. You can make your parser slightly more sophisticated and get dependencies between methods.
Update: or if you have either a *nix or cygwin you can get a list of dependencies as
find com/akshor/pjt33/image -name \*.class |
sed s/\\.class$// |
while read x
do
javap -v $x | grep " = class" | sed "s%.*// *%$x -> %"
done
Add a header and a footer and you can pass it to dot to render a graph. If you just want to know which classes are used by the most other classes, as your question implies, then
find com/akshor/pjt33/image -name \*.class |
sed s/\\.class$// |
while read x
do
javap -v $x | grep " = class" | sed "s%.*// *%%"
done |
sort | uniq -c | sort -n
For advanced code analysis you might wanna have a look at http://www.moosetechnology.org/
Cheers
Thomas
(edit: moved down here by general request, See: How to generate a Java call graph)

Categories