/system/bin/sh: no closing quote How to fix? [duplicate] - java

This question already has an answer here:
Command working in terminal, but "no closing quote" error when used Process.exec
(1 answer)
Closed 8 months ago.
This post was edited and submitted for review 8 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I have the next command that allows me to copy allure results (logs, screenshots of completed tests) from /data/data/com.example/files/allure-results folder (android 10, 11) to sdcard. (i need it because sdcard is private folder on device from android 10 and i use workaround with tar process that allows me to untar required folder to protected sdcard folder)
adb exec-out "run-as com.example sh -c 'cd /data/data/com.example/files && tar cf - allure-results' | tar xvf - -C /sdcard/
When i start it from local computer terminal everything is ok.
But for some reason, i have the next error if i execute this command from code via ProcessBuilder -> /system/bin/sh: no closing quote
command in code looks like:
exec("adb exec-out \"run-as com.example sh -c 'cd /data/data/com.example/files && tar cf - allure-results' | tar xvf - -C /sdcard/\"".split(" "))
How can fix it? Any ideas?
P.S. don't suggest to use TestStorage from androidx.test.services etc it doesn't fit my case and based on scratches for android < 10...
solution pass as array:
https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#exec(java.lang.String%5B%5D)

I think the issue comes from the last "split()" method.
The result of splitting:
"adb exec-out \"run-as ...".split(" ")
is:
"adb", "exec-out", "\"run-as", ...
The third element in the array split() generated has a not closed ".
I would suggest to remove the .split() and to pass exec() an array of three elements.
"adb", "exec-out", "run-as ...The-rest..."

Related

Java fails to create directory / file from the command line [duplicate]

This question already has an answer here:
Java error in making file through console
(1 answer)
Closed 4 years ago.
I have an executable that generates some file, and I need to call this executable from a Java application. The command goes like this
Generator.exe -outputfile="path/to/file" [some other params]
It works fine on the command prompt, but running it from Java,all steps are executed but the file is not created.
I doubt the problem was that my java application is not able to crate files / directories, so I tried to create a directory as below
try {
String envp[] = new String[1];
envp[0] = "PATH=" + System.getProperty("java.library.path");
Runtime.getRuntime().exec("mkdir path/to/folder", envp);
}
catch (Exception e) {
e.printStackTrace();
}
I get the following exception, even If the directory exist
java.io.IOException: Cannot run program "mkdir":
CreateProcess error=2, The system cannot find the file specified
I also tried using java.lang.Process and java.lang.Process and I got the same exception, although the command mkdir path/to/folder works fine on the command prompt
Two points:
1) You don't need to pass in the java.library.path to the mkdir command. Mkdir expects one parameter - the directory/ies you want to created.
2) Why not use the Java File class to create the directory instead? Create a File object of the path, then call the mkdirs() function on it.

Adding Runnable Thread class to JAR file using Terminal

When I try to run the command
jar uvf Century.jar Century$1.class
from the command line, I get the following response:
adding: Century.class(in = 6441) (out= 3544)(deflated 44%)
Notice that instead of adding Century$1.class, is adds Century.class. The issue here is that Century$1.class is the class file for a new runnable thread that gets created in Century.class, which is the main class. Is there some way I can add the Century$1.class file to the jar?
try any of
jar uvf Century.jar Century\$1.class
jar uvf Century.jar 'Century$1.class'
A unix shell will interpret $1 as the value of the first command line parameter which is not what you want, you want the $ verbatim.
And please remember to comment or accept an answer given to your last question Datepicker Multiple Dates not working in Google Apps Script

Malt Parser throwing class not found exception

I'm trying to parse sentence with Malt Parser in NLTK. When I did raw_parse(sent) it gave an error with exit code 1. I executed java command on terminal and it gives class Not Found exception, I don't understand what is wrong now?
java -Xmx1024m -jar /usr/local/bin/malt.jar -w /home/abc/maltparser-1.7.2 -c engmalt.linear-1.7 -i /home/abc/maltparser-1.7.2/malt_input.conllrPZgwc -o /home/abc/maltparser-1.7.2/malt_output.conllDMSKpg -m parse
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Layout
Your working directory is not correctly set. Log4j is a package used by Malt Parser (see: maltparser-1.7.2/lib/log4j.jar). Which is used for logging logically.
In order to run maltparser in NLTK, the working directory should be set to this folder (in your case: /home/abc/maltparser-1.7.2).
So, step one is getting the latest NLTK from git:
git clone https://github.com/nltk/nltk.git
Install NLTK:
sudo python setup.py install
To run Malt Parser using NLTK try this code example:
import os
import nltk
os.environ['MALTPARSERHOME']="/home/abc/maltparser-1.7.2"
verbose = False
maltParser = nltk.parse.malt.MaltParser(working_dir="/home/abc/maltparser-1.7.2",
mco="engmalt.linear-1.7",
additional_java_args=['-Xmx512m'])
print(maltParser.raw_parse('This is a test sentence', verbose=verbose).tree().pprint())
As you may notice I'm using the pre-learned mco file (engmalt.linear-1.7), which can be downloaded from here:
http://www.maltparser.org/mco/english_parser/engmalt.html
Move this mco file to: /home/abc/maltparser-1.7.2 directory.
Finally NLTK only except malt.jar. So create a copy (or rename):
cp maltparser-1.7.2.jar malt.jar
Which can still be located in your /home/abc/maltparser-1.7.2.jar directory.
Hopefully you'll get it running!

Is there a way to get count of number methods used in a jar file

Can i have the count of all methods used in a jar file .
My APK uses certain external JARS and there are a number of classes around hundred to be precise.
I have used decompilers like dex2jar JAD and others to name a few ,but they all seem to show methods only in particular class file.
Is there a way i can get a total count ?
You can convert the jar to a dex file, and then pull the number of method references out of the header. It is stored as an unsigned little endian integer, at offset 88 (0x58).
dx --dex --output=temp.dex orig.jar
cat temp.dex | head -c 92 | tail -c 4 | hexdump -e '1/4 "%d\n"'
Keep in mind that this is the number of unique methods referenced, not the number of method references. In other words, if a particular method is referenced twice in the dex file, it will only be counted once in the count in the header. And when you import this jar into your apk, the method references that are common between the two are deduplicated, so the total method reference count of the final merged apk will be <= the sum of the two.
This gradle plugin https://github.com/KeepSafe/dexcount-gradle-plugin will show you the total method count after assembling and also generates a report with the method count of each package. Which after being sorted looks like this:
30145 com
27704 org
20950 android
17140 org.spongycastle
16605 android.support
9760 com.google
8930 com.fasterxml.jackson
8930 com.fasterxml
8633 android.support.v4
7020 com.fasterxml.jackson.databind
6426 android.support.v7
5311 com.google.protobuf
4705 org.spongycastle.crypto
...
In combination with the gradle command
.\gradlew app:dependencies
which prints out the dependency tree you will get a good overview of which dependency needs how many methods.
Cyvis can read a .jar or .class file, and will show both total method counts plus cyclomatic complexity and instruction count for each method. The GUI is a bit ... portable ... but I've run it on Ubuntu and it says it works on Windows. Seems pretty good for a first-cut source of info on how likely a library is to give you trouble.
Use the http://github.com/mihaip/dex-method-counts for calculationg number of methods from everywhere (JAR, AAR, DEX, APK)
DEX or APK:
./dex-method-counts <your_file_path>.DEX
or
./dex-method-counts <your_file_path>.APK
JAR
just make a DEX from JAR as it was shown above like this:
<your_path_to_android_buil_tools>/dx --dex --output=temp.dex orig.jar
and then
./dex-method-counts temp.dex
AAR
Firstly unzip it (yeah AAR it is ZIP actually) and then use classes.jar as it shown above in JAR section
unzip mylib.aar -d mylib
dx --dex --output=temp.dex mylib/classes.jar
dex-method-counts temp.dex
For cases where you're already over the 64k method limit, an alternate approach would be to use the --multi-dex option to dx, and then use baksmali's "list methods" functionality on all of the dex files that dx generates. Next, you would combine these lists, sort the combined list and remove any duplicates. The number of methods you are left with will be the total method count.
dx --dex --multi-dex --output=out orig.jar
find out -name classes*.dex -exec baksmali list methods {} \; | sort | uniq | wc -l
If you have the source code (or can download it), Sonar will do static analysis like this on it. You can also check a bunch of other complexity metrics which may be useful for what you're trying to do. (Might be nice to tell us what you're trying to do. ;) )
Use the jar program with the -x parameter to extract the files
from your jar file.
Apply a decompiler to each .class file to get the number of methods
in each file.
Add up the method counts.
I just wrote a python script for this to get a rough estimate
import re
import subprocess
import sys
for jarfile in sys.argv[1:]:
class_output = subprocess.check_output(['jar', 'tf', jarfile])
classes = [c.replace('/', '.') for c in re.findall(r'(.*)\.class', class_output)]
methods = []
if classes:
def_out = subprocess.check_output(['javap', '-classpath', jarfile] + classes)
# This is pretty hacky: look for parentheses in the declaration line.
num_methods = sum(1 for line in def_out if '(' in line)
else:
num_methods = 0
print '{} {} {}'.format(num_methods, len(classes), jarfile)
I had just run into the Android 64K method limit, and my dependencies weren't indexed by the methodcount.com service yet.
I wrote a script based on #JesusFreke's answer for this problem and for another problem (https://stackoverflow.com/a/21485222/6643139):
#!/bin/bash
unzip $1 classes.jar -d aarsize &&
dx --dex --output=aarsize/temp.dex aarsize/classes.jar &&
hexdump -s 88 -n 4 -e '1/4 "%d\n"' aarsize/temp.dex &&
rm -rf aarsize
Save it to a file name "aarsize", chmod +x for it, output of aarsize your_aar_file :
$ aarsize status-bar-compat-release.aar
Archive: status-bar-compat-release.aar
inflating: aarsize/classes.jar
91
The 91 is the method counts of your aar file.
To find methods count in gradle library, you can use this -
http://www.methodscount.com
It also provides plugin for android studio.
http://www.methodscount.com/plugins
With the command line, after having unzipped the JAR, something like this should work :
for f in *.class; do javap -c $(basename -s .class $f) | grep invoke | sed 's/.*Method\(.*\)/\1/g'; done | wc -l
(public|protected|private|static|\s) +[\w\<\>\[\]]+\s+(\w+) *\([^\)]*\) *(\{?|[^;])
Search in project using CTRL+SHIFT+F. It helped me

Comparing file size of downloaded file with remote file on ftp server

I am using FTPClient to download files from remote FTP Server.
After downloading, I would like to compare the size of local file and remote file if they are same.
Once the file is downloaded, the size of downloaded file is different from the one in remote server.
Below is the code snippet
FileOutputStream output = new FileOutputStream(localFile.getAbsolutePath());
if( getFTPFileType()!=null ){
// set as binary
ftpClient.setFileType(getFTPFileType(), getFTPFileType());
ftpClient.setFileTransferMode(getFTPFileType());
}
if( getLog().isDebugEnabled()){
getLog().debug("FTP File Type "+getFTPFileType());
}
boolean success = ftpClient.retrieveFile(remoteFile.getName(), output);
If I download in windows environment, it works fine. But if I download in AIX server, there is difference between file sizes. I compared the downloaded files, the content is same.
Please advice.
IF the number of bytes difference in size ~= the number of lines in the file, it is due to the removal of windows carriage control characters: \r or ^M as they appear in vi.
And the content is not the same in the sense that checksums would fail.
Edit:
inside ftp: dir filename will return something like this
-rw-rw-rw- 1 user group 1224 Mar 4 20:22 twrite.c
I have no good idea on how to get your java class to send that command. Check your documentation. When you can get dir working, you can tokenize the string you get back, the fifth field is the number of bytes on the remote side.
Example using unix shell (java will let you run UNIX scripts), after fileA has been dowloaded from remote to local:
local_size=$(ls -l fileA | awk '{print $5}')
/usr/bin/ftp -n <<EOF > ftp.log
open remote_nodename
user username password
cd /directory/to/files
dir fileA
bye
END
remote_size=$(grep 'fileA' ftp.log | awk '{print $5}')
[ $remote_size -eq $local_size ] && echo 'OK' || echo 'NOTOK'
If you can emulate this with java classes okay, otherwise you need to use something like this which shows the use of runtime exec():
http://www.java-samples.com/showtutorial.php?tutorialid=8
Again, to vbe clear ftp does NOT run shell scripts on the remote side. ssh does.

Categories