java实现类linux shell效果

本文探讨了在 Linux 系统中实现 Shell 自动交互的方法,包括使用重定向、管道和 expect 工具等手段,解决了如自动登录、密码修改等常见需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一开始只是想要做一个网页版的linux shell,但是后来做着做着越来越觉得不太靠谱,于是乎,找了好久在国外网站上找到了一个相似的例子。

例子如下:

TestAppliaction.java

package dev.exec.tester;

/**
 * <p>Title: ExecCommander</p>
 * <p>Description: This project serves as a launchpad for development and tests of a component to make use of process execution easier</p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: N/A</p>
 * @author Doron Barak
 * @version 1.0
 */
import java.awt.*;
import javax.swing.*;

public class TestApplication {
	private boolean packFrame = false;
	//Construct the application
	public TestApplication() {
		TestFrame frame = new TestFrame();
		//Validate frames that have preset sizes
		//Pack frames that have useful preferred size info, e.g. from their layout
		if (packFrame) {
			frame.pack();
		} else {
			frame.validate();
		}
		//Center the window
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension frameSize = frame.getSize();
		if (frameSize.height > screenSize.height) {
			frameSize.height = screenSize.height;
		}
		if (frameSize.width > screenSize.width) {
			frameSize.width = screenSize.width;
		}
		frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
		frame.setVisible(true);
	}

	//Main method
	public static void main(String[] args) {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
			e.printStackTrace();
		}
		new TestApplication();
	}
}

TestFrame.java

package dev.exec.tester;

/**
 * <p>Title: ExecCommander</p>
 * <p>Description: This project serves as a launchpad for development and tests of a component to make use of process execution easier</p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: N/A</p>
 * @author Doron Barak
 * @version 1.0
 */

import java.awt.*;
import java.awt.event.*;
import java.io.*;

import javax.swing.*;
import javax.swing.border.*;

import dev.exec.util.*;

public class TestFrame extends JFrame implements ExecProcessor {
	private JPanel contentPane;
	private JMenuBar jMenuBar1 = new JMenuBar();
	private JMenu jMenuFile = new JMenu();
	private JMenuItem jMenuFileExit = new JMenuItem();
	private JMenuItem jMenuHelpAbout = new JMenuItem();
	private JLabel statusBar = new JLabel();
	private BorderLayout borderLayout1 = new BorderLayout();
	private JTextField jTextField1 = new JTextField();
	private JMenuItem jMenuItem1 = new JMenuItem();
	private JTextArea jTextArea1 = new JTextArea();
	private JScrollPane jScrollPane1 = new JScrollPane();
	private ExecHelper exh;
	//Construct the frame
	public TestFrame() {
		enableEvents(AWTEvent.WINDOW_EVENT_MASK);
		try {
			jbInit();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	//Component initialization
	private void jbInit() throws Exception {
		contentPane = (JPanel)this.getContentPane();
		contentPane.setLayout(borderLayout1);
		this.setSize(new Dimension(400, 300));
		this.setTitle("Exec Test Frame");
		statusBar.setBorder(BorderFactory.createEtchedBorder());
		statusBar.setDebugGraphicsOptions(0);
		statusBar.setDoubleBuffered(true);
		statusBar.setOpaque(false);
		statusBar.setVerifyInputWhenFocusTarget(true);
		statusBar.setText(" Ready...");
		jMenuFile.setText("File");
		jMenuFileExit.setText("Exit");
		jMenuFileExit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jMenuFileExitActionPerformed(e);
			}
		});
		jTextField1.setBackground(UIManager.getColor("control"));
		jTextField1.setBorder(BorderFactory.createCompoundBorder(new TitledBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.white, Color.white, new Color(103, 101, 98), new Color(148, 145, 140)), "Input"), BorderFactory.createEmptyBorder( -2, 0, -2, 0)));
		jTextField1.setDoubleBuffered(true);
		jTextField1.setOpaque(false);
		jTextField1.setCaretColor(Color.black);
		jTextField1.setCaretPosition(0);
		jTextField1.setText("");
		jTextField1.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(ActionEvent e) {
				inputActionPerformed(e);
			}
		});
		contentPane.setBackground(UIManager.getColor("control"));
		contentPane.setDoubleBuffered(true);
		contentPane.setOpaque(true);
		jMenuItem1.setText("Run Command.exe");
		jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(ActionEvent e) {
				runCommandActionPerformed(e);
			}
		});
		jTextArea1.setBackground(UIManager.getColor("control"));
		jScrollPane1.getViewport().setBackground(UIManager.getColor("control"));
		jScrollPane1.setAutoscrolls(true);
		jScrollPane1.setBorder(new TitledBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.white, Color.white, new Color(103, 101, 98), new Color(148, 145, 140)), "Output"));
		jScrollPane1.setOpaque(false);
		jTextArea1.setDoubleBuffered(true);
		jTextArea1.setOpaque(false);
		jTextArea1.setText("");
		jTextArea1.setColumns(80);
		jTextArea1.setRows(25);
		jTextArea1.setWrapStyleWord(true);
		jMenuFile.add(jMenuItem1);
		jMenuFile.add(jMenuFileExit);
		jMenuBar1.add(jMenuFile);
		setJMenuBar(jMenuBar1);
		contentPane.add(statusBar, BorderLayout.SOUTH);
		contentPane.add(jTextField1, BorderLayout.NORTH);
		contentPane.add(jScrollPane1, BorderLayout.CENTER);
		jScrollPane1.getViewport().add(jTextArea1, null);
	}

	private void updateTextArea(JTextArea textArea, String line) {
		textArea.append(line);
		textArea.setSelectionStart(textArea.getText().length());
		textArea.setSelectionEnd(textArea.getText().length());
	}

	//File | Exit action performed
	public void jMenuFileExitActionPerformed(ActionEvent e) {
		System.exit(0);
	}

	//Overridden so we can exit when window is closed
	protected void processWindowEvent(WindowEvent e) {
		super.processWindowEvent(e);
		if (e.getID() == WindowEvent.WINDOW_CLOSING) {
			jMenuFileExitActionPerformed(null);
		}
	}

	public void processNewInput(String input) {
		updateTextArea(jTextArea1, input);
	}

	public void processNewError(String error) {
		updateTextArea(jTextArea1, error);
	}

	public void processEnded(int exitValue) {
		exh = null;
		statusBar.setText("Command.exe ended..");
		JOptionPane.showMessageDialog(this, "Exit value for Command.exe was [" + exitValue + "]", "Command.exe is done!", JOptionPane.INFORMATION_MESSAGE);
		try {
			Thread.sleep(1000);
		} catch (InterruptedException ex) {
		}
		jTextArea1.setText(null);
		statusBar.setText("Ready..");
	}

	void runCommandActionPerformed(ActionEvent e) {
		if (exh == null) {
			try {
				exh = ExecHelper.exec(this, "cmd.exe");
				statusBar.setText("Command.exe running..");
			} catch (IOException ex) {
				processNewError(ex.getMessage());
			}
		}
	}

	void inputActionPerformed(ActionEvent e) {
		if (exh != null) {
			exh.println(jTextField1.getText());
			jTextField1.setText(null);
		}
	}
}

ExecHelper.java

package dev.exec.util;

/**
 * <p>Title: ExecCommander</p>
 * <p>Description: This project serves as a launchpad for development and tests of a component to make use of process execution easier</p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: N/A</p>
 * @author Doron Barak
 * @version 1.0
 */
import java.io.*;

public class ExecHelper implements Runnable {
	// Allocate 1K buffers for Input and Error Streams..
	private byte[] inBuffer = new byte[1024];
	private byte[] errBuffer = new byte[1024];
	// Declare internal variables we will need..
	private Process process;
	private InputStream pErrorStream;
	private InputStream pInputStream;
	private OutputStream pOutputStream;
	private PrintWriter outputWriter;
	private Thread processThread;
	private Thread inReadThread;
	private Thread errReadThread;
	private ExecProcessor handler;
	// Private constructor so that no one can create a new ExecHelper directly..
	private ExecHelper(ExecProcessor ep, Process p) {
		// Save variables..
		handler = ep;
		process = p;
		// Get the streams..
		pErrorStream = process.getErrorStream();
		pInputStream = process.getInputStream();
		pOutputStream = process.getOutputStream();
		// Create a PrintWriter on top of the output stream..
		outputWriter = new PrintWriter(pOutputStream, true);
		// Create the threads and start them..
		processThread = new Thread(this);
		inReadThread = new Thread(this);
		errReadThread = new Thread(this);
		// Start Threads..
		processThread.start();
		inReadThread.start();
		errReadThread.start();
	}

	private void processEnded(int exitValue) {
		// Handle process end..
		handler.processEnded(exitValue);
	}

	private void processNewInput(String input) {
		// Handle process new input..
		handler.processNewInput(input);
	}

	private void processNewError(String error) {
		// Handle process new error..
		handler.processNewError(error);
	}

	// Run the command and return the ExecHelper wrapper object..
	public static ExecHelper exec(ExecProcessor handler, String command) throws IOException {
		return new ExecHelper(handler, Runtime.getRuntime().exec(command));
	}

	// Print the output string through the print writer..
	public void print(String output) {
		outputWriter.print(output);
	}

	// Print the output string (and a CRLF pair) through the print writer..
	public void println(String output) {
		outputWriter.println(output);
	}

	public void run() {
		// Are we on the process Thread?
		if (processThread == Thread.currentThread()) {
			try {
				// This Thread just waits for the process to end and notifies the handler..
				processEnded(process.waitFor());
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
			// Are we on the InputRead Thread?
		} else if (inReadThread == Thread.currentThread()) {
			try {
				// Read the InputStream in a loop until we find no more bytes to read..
				for (int i = 0; i > -1; i = pInputStream.read(inBuffer)) {
					// We have a new segment of input, so process it as a String..
					processNewInput(new String(inBuffer, 0, i));
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
			// Are we on the ErrorRead Thread?
		} else if (errReadThread == Thread.currentThread()) {
			try {
				// Read the ErrorStream in a loop until we find no more bytes to read..
				for (int i = 0; i > -1; i = pErrorStream.read(errBuffer)) {
					// We have a new segment of error, so process it as a String..
					processNewError(new String(errBuffer, 0, i));
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}
}

ExecProcessor.java

package dev.exec.util;

/**
 * <p>Title: ExecCommander</p>
 * <p>Description: This project serves as a launchpad for development and tests of a component to make use of process execution easier</p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: N/A</p>
 * @author Doron Barak
 * @version 1.0
 */
public interface ExecProcessor {
	// This method gets called when the process sent us a new input String..
	public void processNewInput(String input);

	// This method gets called when the process sent us a new error String..
	public void processNewError(String error);

	// This method gets called when the process has ended..
	public void processEnded(int exitValue);
}

以上代码是客户端的shell实现,亲自试了一下,适用于window系统,但是在linux中无法实现交互功能,自己在上面修修补补也还是实现不了,谁实现出来麻烦联系我哈。

其实抛开这个话题,Linux Shell的自动交互是可以通过某些操作来实现的。

以下内容引用其他网站,原地址:Linux Shell自动交互

/*reference start*/

你了解Linux系统么?你是Linux系统的应用者么?如果你要学习linux,你可能会遇到Linux Shell自动交互问题,这里将介绍Linux Shell自动交互的解决方法,在这里拿出来和大家分享一下。

一、背景

shell脚本在处理自动循环或大的任务方面可节省大量的时间,通过创建一个处理任务的命令清单,使用变量、条件、算术和循环等方法快速创建脚本以完成相应工作,这比在命令行下一个个敲入命令要省时省力得多。

但是有时候我们可能会需要实现和交互程序如ftp,telnet服务器等进行交互的功能,这时候我们需要用到shell的自动交互功能,本文收集了较常用的三种自动交互方法,并进行了比较和总结。

二、需求

需求1:
从一台Linux机器ftp登陆到另一台Linux机器,进行系列操作后关闭,懒得每次都手动输入密码。

需求2:
改变登录用户密码,懒得每次都输入新旧密码。

需求3:
希望su自动登录到root账户,懒得每次都输入root密码。

三、调试环境

终端:SecureCRT

系统:WinXP, CentOS 4.4(VmWare)

Shell:bash

注:shell有很多种,B类SHELL(sh, bash, ksh)之间行为相近;C类SHELL(csh, tcsh)之间行为相近,还有zsh和rc等shell,本文的调试环境是bash。

四、自动交互方法一

自动交互最关键的就是交互信息的自动输入,首先联想到文件重定向,在shell编程中有这样一种用法(参考Linux与UNIX SHELL编程指南 chapt 5.7):"command << delimiter  从标准输入中读入,直至遇到delimiter分界符。"

重定向操作符command << delimiter是一种非常有用的命令,shell将分界符delimiter之后直至下一个同样的分界符之前的所有内容都作为输入,遇到下一个分界符, shell就知道输入结束了。最常见的delimiter分界符是EOF,当然完全可以自定为其他字符。

对于需求1 要求的自动登陆ftp,并作系列操作,则可以用这种方法进行自动交互。代码如下:

 
  1. #!/bin/bash  
  2. ftp -i -n 192.168.167.187 << EOF 
  3. user hzc 123456  
  4. pwd  
  5. cd test  
  6. pwd  
  7. close  
  8. bye  
  9. EOF 

测试可以发现,如上代码使用帐号名hzc,密码123456成功登陆了ftp服务器,并进入目录,打印出了pwd。

五、自动交互方法二

需求2中要求采用非交互的方式改变登录用户密码,尝试用方法1,无法实现。

这时候联想到交互信息的另一个自动输入方法,管道,通过echo + sleep + | 可以实现这个需求。

 
  1. #!/bin/bash  
  2. (echo "curpassword"  
  3. sleep 1  
  4. echo "newpassword"   
  5. sleep 1  
  6. echo "newpassword")|passwd 

测试通过,运行这个脚本,直接把当前用户的curpassword改成newpassword。

六、自动交互方法三

需求3中要求自动登录root账号,尝试方法1和方法2,都出现错误提示standard in must be a tty。

这时候尝试寻找外部帮助,一个shell工具expect可以实现这个功能,其实expect就是一个专门用来实现自动交互功能的工具,expect的语法可以参考相关资料,代码如下:

 
  1. #!/usr/bin/expect  
  2. spawn su root  
  3. expect "password: "  
  4. send "123456\r"  
  5. expect eof  
  6. exit 

测试通过,运行这个脚本,直接从当前用户登录到root用户。

七、方法总结

方法一(重定向)简单直观,也经常有实际应用,但是在自动交互领域功能有限。

方法二(管道)也很简单直观,有时甚至不用sleep配合就能展现强大的自动交互实力,但是在某些时候也束手无策。

方法三(expect)在功能上是最为强大的,expect本来就是为实现自动交互功能而生,但是缺点是需要安装expect包,在嵌入式等环境下难以安装。

三个方法各有优劣,应用的好,都可以完成Linux Shell自动交互。

/*reference end*/


===========================================================================================================================


我自己研究了一下第三种,这种方法主要是使用一个工具expect,而expect又是建立在tcl之上的,所以要得先安装tcl才装expect。

以下内容引用其他网站,原地址:linux expect 安装

/*reference start*/

Expect是在Tcl基础上创建起来的,它还提供了一些Tcl所没有的命令,它可以用来做一些linux下无法做到交互的一些命令操作,在远程管 理方面发挥很大的作用。
spawn命令激活一个Unix程序来进行交互式的运行。 
send命令向进程发送字符串。
expect 命令等待进程的某些字符串。 
expect支持正规表达式并能同时等待多个字符串,并对每一个字符串执行不同的操作.


A. Tcl 安装
主页: http://www.tcl.tk
下载地址: http://www.tcl.tk/software/tcltk/downloadnow84.tml

1.下载源码包
wget http://nchc.dl.sourceforge.net/sourceforge/tcl/tcl8.4.11-src.tar.gz

2.解压缩源码包
tar xfvz tcl8.4.11-src.tar.gz

3.安装配置
cd tcl8.4.11/unix
./configure --prefix=/usr/tcl --enable-shared
make
make install

安装完毕以后,进入tcl源代码的根目录,把子目录unix下面的tclUnixPort.h copy到子目录generic中。
暂时不要删除tcl源代码,因为expect的安装过程还需要用。

B. expect 安装 (需Tcl的库)
主页: http://expect.nist.gov/

1.下载源码包
wget http://sourceforge.net/projects/expect/files/Expect/5.45/expect5.45.tar.gz/download

2.解压缩源码包
tar xzvf expect5.45.tar.gz

3.安装配置
cd expect5.45
./configure --prefix=/usr/expect --with-tcl=/usr/tcl/lib --with-tclinclude=../tcl8.4.11/generic

make
make install
ln -s /usr/tcl/bin/expect /usr/expect/bin/expect

/*reference end*/




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值