java shell_Java中执行shell笔记

转载:https://www.cnblogs.com/jevan/p/3169617.html

java中执行shell有好几种方式:第一种(exec)方式一public static synchronized void runshell2()

{

File superuser = new File("/system/bin/superuser");

if (superuser.exists())

{

// return device to original state

Process process;

try

{

process = Runtime.getRuntime().exec("superuser");

DataOutputStream os = new DataOutputStream(process.getOutputStream());

os.writeBytes("mount -oremount,rw /dev/block/mtdblock3 /system\n");

os.writeBytes("busybox cp /system/bin/superuser /system/bin/su\n");

os.writeBytes("busybox chown 0:0 /system/bin/su\n");

os.writeBytes("chmod 4755 /system/bin/su\n");

os.writeBytes("rm /system/bin/superuser\n");

os.writeBytes("/system/bin/monkey -v 100\n");

os.writeBytes("exit\n");

os.flush();

} catch (Exception e)

{

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

第一种(exec)方式二:public static synchronized void runshell3()

{

String cmd = "sendkey 3 2\n";

try

{

Process exeEcho = Runtime.getRuntime().exec("su");

exeEcho.getOutputStream().write(cmd.getBytes());

exeEcho.getOutputStream().flush();

} catch (IOException e)

{

//showMessage("Excute exception: " + e.getMessage());

e.printStackTrace();

}

}

第二种方式一:public static synchronized void runShell() {

ProcessBuilder pb = new ProcessBuilder("/system/bin/sh");

// java.lang.ProcessBuilder: Creates operating system processes.

pb.directory(new File("/system/bin"));// 设置shell的当前目录。

try {

Process proc = pb.start();

// 获取输入流,可以通过它获取SHELL的输出。

BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));

BufferedReader err = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

// 获取输出流,可以通过它向SHELL发送命令。

PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);

out.println("pwd");

out.println("su root");// 执行这一句时会弹出对话框(以下程序要求授予最高权限...),要求用户确认。

// out.println("cat /proc/version");

// out.println("monkey -v 500");

// out.println("cd /data/data");//这个目录在系统中要求有root权限才可以访问的。

// out.println("ls -l");//这个命令如果能列出当前安装的APK的数据文件存放目录,就说明我们有了ROOT权限。

out.println("exit");

// proc.waitFor();

String line;

while ((line = in.readLine()) != null) {

System.out.println(line); // 打印输出结果

}

while ((line = err.readLine()) != null) {

System.out.println(line); // 打印错误输出结果

}

in.close();

out.close();

proc.destroy();

} catch (Exception e) {

System.out.println("exception:" + e);

}

}

第二种方式二:/**

* 执行一个shell命令,并返回字符串值

*

* @param cmd

* 命令名称&参数组成的数组(例如:{"/system/bin/cat", "/proc/version"})

* @param workdirectory

* 命令执行路径(例如:"system/bin/")

* @return 执行结果组成的字符串

* @throws IOException

*/

public static synchronized String run(String[] cmd, String workdirectory) {

StringBuffer result = new StringBuffer();

try {

ProcessBuilder builder = new ProcessBuilder(cmd);

InputStream in = null;

// 设置一个路径(绝对路径了就不一定需要)

if (workdirectory != null) {

// 设置工作目录(同上)

builder.directory(new File(workdirectory));

// 合并标准错误和标准输出

builder.redirectErrorStream(true);

// 启动一个新进程

Process process = builder.start();

// 读取进程标准输出流

in = process.getInputStream();

byte[] re = new byte[1024];

while (in.read(re) != -1) {

result = result.append(new String(re));

}

}

// 关闭输入流

if (in != null) {

in.close();

}

} catch (Exception ex) {

ex.printStackTrace();

}

return result.toString();

}

笔记:

今天使用第一种,发现了以下问题:/**

* 执行shell

*

* @return 0:成功,其它为失败。

*/

public static synchronized int runShellCmd() {

BufferedReader input = null;

PrintWriter output = null;

Process pro = null;

try {

pro = Runtime.getRuntime().exec("adb shell");

input = new BufferedReader(new InputStreamReader(pro.getInputStream()));

pro.getOutputStream().write("pidof mediaserver\r\n".getBytes());

pro.getOutputStream().flush();

String line = input.readLine();

int pid = 0;

/**

* 按道理说直接执行命令打印是这样的:

* root@android:/ # adb shell

* root@android:/ # pidof mediaserver

* 7114

* 也就是说第三行就应该是我取到的pid值,但是实际上却是5行?

*/

for (int i = 0; i < 6; i++) {

Log.e(TAG , i + "line is" + line);

pid = toInt(line, 0);

if (pid > 0)

break;

line = input.readLine();

}

Log.e(TAG, "pid:" + pid);

/**

* 实际打印如下:

* E/MainActivity( 7036): 0 line is pidof mediaserver

* E/MainActivity( 7036): 1 line is

* E/MainActivity( 7036): 2 line is root@android:/ # pidof mediaserver

* E/MainActivity( 7036): 3 line is

* E/MainActivity( 7036): 4 line is 6946

* E/MainActivity( 7036): pid:6946

* 为什么会多出2个空行??

*/

if (pid == 0) {

throw new IOException("not find mediaserver process!");

}

String killCmd = String.format("kill -9 %d\r\n", pid);

/**

* 直接这么使用不行的,不知道什么原因,执行结果死活不对。

*/

pro.getOutputStream().write(killCmd.getBytes());

pro.getOutputStream().flush();

/**

* 再一次这么重开就ok了,谁能告诉我原因?

*/

pro.destroy();

pro = null;

pro = Runtime.getRuntime().exec("adb shell");

pro.getOutputStream().write(killCmd.getBytes());

pro.getOutputStream().flush();

} catch (IOException ex) {

ex.printStackTrace();

return -1;

} finally {

try {

if (input != null) {

input.close();

}

if (output != null) {

output.close();

}

} catch (IOException e) {

e.printStackTrace();

}

if (pro != null) {

pro.destroy();

pro = null;

}

}

return 0;

}

我去看看源码是怎么样的!

Runtime的exec最终调用的是ProcessManager,代码如下所示:/**

* Executes the specified command and its arguments in a separate native

* process. The new process uses the environment provided in {@code envp}

* and the working directory specified by {@code directory}.

*

* @param progArray

* the array containing the program to execute as well as any

* arguments to the program.

* @param envp

* the array containing the environment to start the new process

* in.

* @param directory

* the directory in which to execute the program. If {@code null},

* execute if in the same directory as the parent process.

* @return the new {@code Process} object that represents the native

* process.

* @throws IOException

* if the requested program can not be executed.

* @throws SecurityException

* if the current {@code SecurityManager} disallows program

* execution.

* @see SecurityManager#checkExec

* @since Android 1.0

*/

public Process exec(String[] progArray, String[] envp, File directory) throws IOException {

// BEGIN android-changed: push responsibility for argument checking into ProcessManager

return ProcessManager.getInstance().exec(progArray, envp, directory, false);

// END android-changed

}

ProcessManager的exec代码如下:/**

* Map from pid to Process. We keep weak references to the Process objects

* and clean up the entries when no more external references are left. The

* process objects themselves don't require much memory, but file

* descriptors (associated with stdin/out/err in this case) can be

* a scarce resource.

*/

private final Map processReferences

= new HashMap();

/**

* Executes a process and returns an object representing it.

*/

Process exec(String[] taintedCommand, String[] taintedEnvironment, File workingDirectory,

boolean redirectErrorStream) throws IOException {

// Make sure we throw the same exceptions as the RI.

if (taintedCommand == null) {

throw new NullPointerException();

}

if (taintedCommand.length == 0) {

throw new IndexOutOfBoundsException();

}

// Handle security and safety by copying mutable inputs and checking them.

String[] command = taintedCommand.clone();

String[] environment = taintedEnvironment != null ? taintedEnvironment.clone() : null;

SecurityManager securityManager = System.getSecurityManager();

if (securityManager != null) {

securityManager.checkExec(command[0]);//权限检查

}

// Check we're not passing null Strings to the native exec.

for (String arg : command) {

if (arg == null) {

throw new NullPointerException();

}

}

// The environment is allowed to be null or empty, but no element may be null.

if (environment != null) {

for (String env : environment) {

if (env == null) {

throw new NullPointerException();

}

}

}

FileDescriptor in = new FileDescriptor();

FileDescriptor out = new FileDescriptor();

FileDescriptor err = new FileDescriptor();

String workingPath = (workingDirectory == null)

? null

: workingDirectory.getPath();

// Ensure onExit() doesn't access the process map before we add our

// entry.

synchronized (processReferences) {

int pid;

try {

/**

* 调用exec函数

*/

pid = exec(command, environment, workingPath, in, out, err, redirectErrorStream);

} catch (IOException e) {

IOException wrapper = new IOException("Error running exec()."

+ "Command:" + Arrays.toString(command)

+ "Working Directory:" + workingDirectory

+ "Environment:" + Arrays.toString(environment));

wrapper.initCause(e);

throw wrapper;

}

/**

* 新建一个进程实现。

*/

ProcessImpl process = new ProcessImpl(pid, in, out, err);

/**

* 创建一个进程引用。

*/

ProcessReference processReference

= new ProcessReference(process, referenceQueue);

/**

* 加入到全局进程引用map中。

*/

processReferences.put(pid, processReference);

/*

* This will wake up the child monitor thread in case there

* weren't previously any children to wait on.

*/

processReferences.notifyAll();

return process;

}

}

本地exec的原型:/**

* Executes a native process. Fills in in, out, and err and returns the

* new process ID upon success.

*/

static native int exec(String[] command, String[] environment,

String workingDirectory, FileDescriptor in, FileDescriptor out,

FileDescriptor err, boolean redirectErrorStream) throws IOException;

对应的native文件为://Android 4.0.3在

./libcore/luni/src/main/native/java_lang_ProcessManager.cpp

//Android 2.2在

./dalvik/libcore/luni-kernel/src/main/native/java_lang_ProcessManager.cpp

//源码为:

/**

* Converts Java String[] to char** and delegates to executeProcess().

*/

static pid_t java_lang_ProcessManager_exec(

JNIEnv* env, jclass clazz, jobjectArray javaCommands,

jobjectArray javaEnvironment, jstring javaWorkingDirectory,

jobject inDescriptor, jobject outDescriptor, jobject errDescriptor,

jboolean redirectErrorStream) {

// Copy commands into char*[].

char** commands = convertStrings(env, javaCommands);

// Extract working directory string.

const char* workingDirectory = NULL;

if (javaWorkingDirectory != NULL) {

workingDirectory = env->GetStringUTFChars(javaWorkingDirectory, NULL);

}

// Convert environment array.

char** environment = convertStrings(env, javaEnvironment);

//关键就这一行.

pid_t result = executeProcess(

env, commands, environment, workingDirectory,

inDescriptor, outDescriptor, errDescriptor, redirectErrorStream);

// Temporarily clear exception so we can clean up.

jthrowable exception = env->ExceptionOccurred();

env->ExceptionClear();

freeStrings(env, javaEnvironment, environment);

// Clean up working directory string.

if (javaWorkingDirectory != NULL) {

env->ReleaseStringUTFChars(javaWorkingDirectory, workingDirectory);

}

freeStrings(env, javaCommands, commands);

// Re-throw exception if present.

if (exception != NULL) {

if (env->Throw(exception) < 0) {

LOGE("Error rethrowing exception!");

}

}

return result;

}

看看executeProcess接口,其实源码注释写的很清楚。/** Executes a command in a child process. */

static pid_t executeProcess(JNIEnv* env, char** commands, char** environment,

const char* workingDirectory, jobject inDescriptor,

jobject outDescriptor, jobject errDescriptor,

jboolean redirectErrorStream) {

int i, result, error;

// Create 4 pipes: stdin, stdout, stderr, and an exec() status pipe.

int pipes[PIPE_COUNT * 2] = { -1, -1, -1, -1, -1, -1, -1, -1 };

for (i = 0; i < PIPE_COUNT; i++) {

if (pipe(pipes + i * 2) == -1) {

jniThrowIOException(env, errno);

closePipes(pipes, -1);

return -1;

}

}

int stdinIn = pipes[0];

int stdinOut = pipes[1];

int stdoutIn = pipes[2];

int stdoutOut = pipes[3];

int stderrIn = pipes[4];

int stderrOut = pipes[5];

int statusIn = pipes[6];

int statusOut = pipes[7];

pid_t childPid = fork();

// If fork() failed...

if (childPid == -1) {

jniThrowIOException(env, errno);

closePipes(pipes, -1);

return -1;

}

// If this is the child process...

if (childPid == 0) {

/*

* Note: We cannot malloc() or free() after this point!

* A no-longer-running thread may be holding on to the heap lock, and

* an attempt to malloc() or free() would result in deadlock.

*/

// Replace stdin, out, and err with pipes.

dup2(stdinIn, 0);

dup2(stdoutOut, 1);

if (redirectErrorStream) {

dup2(stdoutOut, 2);

} else {

dup2(stderrOut, 2);

}

// Close all but statusOut. This saves some work in the next step.

closePipes(pipes, statusOut);

// Make statusOut automatically close if execvp() succeeds.

fcntl(statusOut, F_SETFD, FD_CLOEXEC);

// Close remaining open fds with the exception of statusOut.

closeNonStandardFds(statusOut);

// Switch to working directory.

if (workingDirectory != NULL) {

if (chdir(workingDirectory) == -1) {

goto execFailed;

}

}

// Set up environment.

if (environment != NULL) {

environ = environment;

}

// Execute process. By convention, the first argument in the arg array

// should be the command itself. In fact, I get segfaults when this

// isn't the case.

execvp(commands[0], commands);

// If we got here, execvp() failed or the working dir was invalid.

execFailed:

error = errno;

write(statusOut, &error, sizeof(int));

close(statusOut);

exit(error);

}

// This is the parent process.

// Close child's pipe ends.

close(stdinIn);

close(stdoutOut);

close(stderrOut);

close(statusOut);

// Check status pipe for an error code. If execvp() succeeds, the other

// end of the pipe should automatically close, in which case, we'll read

// nothing.

int count = read(statusIn, &result, sizeof(int));

close(statusIn);

if (count > 0) {

jniThrowIOException(env, result);

close(stdoutIn);

close(stdinOut);

close(stderrIn);

return -1;

}

// Fill in file descriptor wrappers.

jniSetFileDescriptorOfFD(env, inDescriptor, stdoutIn);

jniSetFileDescriptorOfFD(env, outDescriptor, stdinOut);

jniSetFileDescriptorOfFD(env, errDescriptor, stderrIn);

return childPid;

}

至此,Runtime的exec就全部结束了。如果对下面的fork,execvp这2个函数不了解。建议看看APU。

最后来看看ProcessBuilder类的实现:/**

* Starts a new process based on the current state of this process builder.

*

* @return the new {@code Process} instance.

* @throws NullPointerException

* if any of the elements of {@link #command()} is {@code null}.

* @throws IndexOutOfBoundsException

* if {@link #command()} is empty.

* @throws SecurityException

* if {@link SecurityManager#checkExec(String)} doesn't allow

* process creation.

* @throws IOException

* if an I/O error happens.

*/

public Process start() throws IOException {

// BEGIN android-changed: push responsibility for argument checking into ProcessManager

String[] cmdArray = command.toArray(new String[command.size()]);

String[] envArray = new String[environment.size()];

int i = 0;

for (Map.Entry entry : environment.entrySet()) {

envArray[i++] = entry.getKey() + "=" + entry.getValue(); //$NON-NLS-1$

}

//和Runtime.exec的一样。

return ProcessManager.getInstance().exec(cmdArray, envArray, directory, redirectErrorStream);

// END android-changed

}

殊路同归!!!哈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Java结合Shell脚本来清洗数据。首先,你可以使用Java编写一个程序,使用Spark Streaming消费Kafka的数据。你可以使用以下命令来启动这个程序: ``` nohup java -jar -Dloader.main=com.suncnpap.etl.kafka.consumer.Kafka10Consumer dataintell-etl-1.0.0.jar -p `pwd`/conf/official_520000.json > logs/official_520000.log 2>&1 & ``` 这个命令会启动一个Java程序,消费Kafka的数据,并将清洗后的数据写入日志文件official_520000.log。 接下来,你可以编写一个Shell脚本来将清洗后的数据迁移到MongoDB。你可以使用以下命令来导出数据: ``` mongoexport -d DataIntell -c official_520000_clean_test --type=json -o official_520000_clean_test.json ``` 然后,你可以使用以下命令将导出的数据导入到MongoDB: ``` mongoimport -d DataIntell -c official520000 --type=json --file official_520000_clean_test.json ``` 最后,你可以使用Shell脚本定时执行这些操作,以实现自动清洗数据的功能。你可以使用以下命令来定时执行Shell脚本: ``` crontab -e ``` 然后在打开的文件添加以下内容: ``` 0 0 * * * /path/to/your/script.sh ``` 这样,每天午夜时分,Shell脚本就会自动执行,清洗数据并将其导入到MongoDB。 #### 引用[.reference_title] - *1* *2* [Shell脚本 (bash)----附带 数据迁移,sparkstreaming消费kafka脚本](https://blog.csdn.net/qq_18453581/article/details/113886221)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [【大数据清洗和预处理】1.8HDFS的shell操作(2)(学习笔记)](https://blog.csdn.net/weixin_63745352/article/details/128025874)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值