Project2:
Creating a Shell Interface
一、實驗環境
Ubuntu 10.04系統
Eclipse開發平臺
二、實驗過程:
1、新建java project,編寫代碼
程序大體思路:
1、程序初始化:初始化數組commandHistory以存儲歷史命令、MyPath存放當前路徑、commandLine存放讀入的命令,以及其他變量
2、做while主循環,不停讀入用戶輸入的命令
3、對命令進行判斷、操作
3.1 如果命令是以“!”開頭,判斷後面的數據未超範圍後,讀取歷史命令:把歷史命令賦值給commandLine。之後進行其他命令的判斷,就可以在一個循環中完成讀取歷史名利的操作。
3.2 以“ ”(空格)分隔命令,存入lineSplit中。
3.3 如果是退出命令,調用System.exit(0)退出。
3.4 如果首個命令是cd命令:根據後邊參數是否以“/”開頭分爲絕對路徑、相對路徑兩部分。
絕對路徑:以“/”分隔路徑,存入currentSplit中。之後逐層對路徑進行判斷,currentPath存放當前判斷路徑:新建ls命令的進程,並使進程路徑爲currentPath,以其輸出與下一級路徑比對,無誤進行下次判斷,否則提示錯誤,開始下次主循環。路徑全對後,對MyPath修改,cd命令執行完畢。
相對路徑:與絕對路徑大體相似,但currentPath初值爲當前路徑,最後對MyPath賦值是在原來MyPath基礎上改變。
3.5 其餘命令,新建輸入命令的進程,設置進程路徑爲MyPath後執行,輸出進程輸出。
2、運行並測試
此程序可實現較簡單的shell功能:1、基本命令:如ls、pwd等等;2、工作路徑的變換:cd命令;3、記錄命令歷史,並可通過“!!”“!*”調用。
此shell中存在很多bug,尤其是在!操作、cd操作中,已經添加代碼如測試cd命令路徑等改正一些問題,但還並不完善。
3、在實驗中遇到的一些問題
在對修改路徑cd命令處理時,想用System.setProperty()函數對程序的路徑進行直接修改,發現始終無法達到效果。網上查詢後,得知這個路徑是寫保護的,無法通過此方法修改。之後想到解決辦法:cd命令先把路徑記錄在MyPath中,在之後的命令新建進程時,通過調用
public ProsessBuilder director(File director)函數對進程路徑修改後,開啓進程即可。
在cd命令對路徑的判斷上,我也下了較大力氣。首先想到新建“ls”進程進行以此判斷,然後發現cd可以有相對路徑、絕對路徑兩種輸入,又進行了判斷。後來又想到多個路徑連在一起的輸入,又通過“/”分隔,加入for循環逐層對路徑進行判斷,某層路徑錯誤後就報錯,停止下層判斷。現在本程序支持絕對、相對路徑輸入,並支持“/home/rongry/experiment/”類型了輸入,但有時候會出現錯誤。
三、實驗總結
在這個實驗中,我首次接觸了java語言,遇到了不上語言上的麻煩錯誤。最後通過網絡查詢、查看java幫助文檔、老師所給材料還是一一解決了。
這次實驗,在“cd”命令等問題上上下了不少功夫。通過這個實驗加深了我對process、shell等內容的理解,也讓我學習了一下java語言的內容。
附:原代碼如下:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class SimpleShell
{
public static void main(String[] args) throws java.io.IOException {
//存放讀入的命令
String commandLine;
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
//當前路徑,賦值爲起始路徑
String MyPath=System.getProperty("user.dir");
//存放歷史命令
ArrayList<String> commandHistory=new ArrayList<String>();
//表示讀取歷史命令時,讀取之前第tem的命令
int tem=0;
//主循環
while (true) {
//讀入命令
System.out.print("jsh>");
commandLine = console.readLine();
commandHistory.add(commandLine);
//沒有命令輸入,開始下一次循環
if (commandLine.equalsIgnoreCase("")) {
commandHistory.remove(commandHistory.size()-1);
continue;
}
//輸入命令以“!”開始,進行讀取歷史命令的操作
if(commandLine.charAt(0)=='!'){
commandHistory.remove(commandHistory.size()-1);
tem=0;
//輸入的“!!”,設置tem=1
if(commandLine.length()==2&&commandLine.charAt(1)=='!'){
tem=1;
}
//輸入爲“!*”,根據*值設施tem值
else {
for(int i=1;i<commandLine.length();i++){
tem=tem*10+commandLine.charAt(i)-48;
}
}
//判斷是否超範圍
if(tem>commandHistory.size()){
System.out.print(tem);System.out.print("error:event not found! \n");
System.out.print(commandHistory.size());
continue;
}
//未超範圍,讀取歷史命令賦給commandLine,繼續之後操作
else{
String exCommand=commandHistory.get(commandHistory.size()-tem);
System.out.print(exCommand+"\n");
commandLine=exCommand;
}
}
//分割所得命令
ArrayList<String> parms = new ArrayList<String>();
String[] lineSplit = commandLine.split(" ");
int size = lineSplit.length;
for (int i=0; i<size; i++) {
parms.add(lineSplit[i]);
}
//退出命令
if(lineSplit[0].equalsIgnoreCase("exit")||lineSplit[0].equalsIgnoreCase("quit")) {
System.out.println("Goodbye");
commandHistory.clear();
System.exit(0);
}
//“cd”命令
else if(lineSplit[0].equalsIgnoreCase("cd")){
//絕對路徑部分
if (lineSplit[1].charAt(0) == '/') {
//以“/”分割,逐層判斷路徑是否正確
String[] currentSplit = lineSplit[1].split("/");
String currentPath = "/";
boolean currentFlag=true;
//新建“ls”命令的進程,以其輸出爲標準進行判斷
for (int i = 1; i < currentSplit.length; i++) {
ProcessBuilder pb = new ProcessBuilder("ls");
File filedir = new File(currentPath);
pb.directory(filedir);
Process proc = pb.start();
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
boolean flag = false;
while ((line = br.readLine()) != null) {
if (currentSplit[i].equalsIgnoreCase(line)) {
flag = true;
break;
}
}
br.close();
//本層正確,進行下一層判斷,否則報錯,路徑不變
if (flag) {
currentPath=currentPath+ "/" +currentSplit[i];
continue;
} else {
System.out.print("error:沒有那個文件或目錄!\n");
currentFlag=false;
break;
}
}
//如果全部路徑無誤,更改MyPath
if(currentFlag){
MyPath = lineSplit[1];
}
} else {
//相對路徑部分,與絕對路徑相似
String[] currentSplit = lineSplit[1].split("/");
String currentPath =MyPath;
boolean currentFlag=true;
for (int i = 0; i < currentSplit.length; i++) {
ProcessBuilder pb = new ProcessBuilder("ls");
File filedir = new File(currentPath);
pb.directory(filedir);
Process proc = pb.start();
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
// read what is returned by the command
String line;
boolean flag = false;
while ((line = br.readLine()) != null) {
if (currentSplit[i].equalsIgnoreCase(line)) {
flag = true;
break;
}
}
br.close();
if (flag) {
currentPath=currentPath+ "/" + currentSplit[i];
continue;
} else {
System.out.print("error: 沒有那個文件或目錄!\n");
currentFlag=false;
break;
}
}
if(currentFlag){
MyPath = MyPath + "/" + lineSplit[1];
}
}
//其餘命令部分
else{
//以此命令啓動進程
ProcessBuilder pb = new ProcessBuilder(parms);
//設置進程的路徑爲當前路徑
File filedir=new File(MyPath);
pb.directory(filedir);
Process proc = pb.start();
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
// 輸出結果
String line;
while ( (line = br.readLine()) != null){
System.out.println(line);
}
br.close();
}
}
}
}