一开始只是想要做一个网页版的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,并作系列操作,则可以用这种方法进行自动交互。代码如下:
- #!/bin/bash
- ftp -i -n 192.168.167.187 << EOF
- user hzc 123456
- pwd
- cd test
- pwd
- close
- bye
- EOF
测试可以发现,如上代码使用帐号名hzc,密码123456成功登陆了ftp服务器,并进入目录,打印出了pwd。
五、自动交互方法二
需求2中要求采用非交互的方式改变登录用户密码,尝试用方法1,无法实现。
这时候联想到交互信息的另一个自动输入方法,管道,通过echo + sleep + | 可以实现这个需求。
- #!/bin/bash
- (echo "curpassword"
- sleep 1
- echo "newpassword"
- sleep 1
- echo "newpassword")|passwd
测试通过,运行这个脚本,直接把当前用户的curpassword改成newpassword。
六、自动交互方法三
需求3中要求自动登录root账号,尝试方法1和方法2,都出现错误提示standard in must be a tty。
这时候尝试寻找外部帮助,一个shell工具expect可以实现这个功能,其实expect就是一个专门用来实现自动交互功能的工具,expect的语法可以参考相关资料,代码如下:
- #!/usr/bin/expect
- spawn su root
- expect "password: "
- send "123456\r"
- expect eof
- 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*/