《操作系统概念》实验一:创建一个shell接口(java)

基本思路:

首先我们要知道什么是shell。在linux中,shell只是一个操作系统的外壳,用户在命令行中输入命令,经由shell传入操作系统中调用系统函数。说具体点,就是输入一条指令,如ls命令,系统是调用/usr/bin文件夹下的ls文件进行操作的,所以系统没有找不到这些命令对于的文件就报错。

所以我们做一个shell接口,就是通过java新建一个子进程,命令从父进程传给子进程,子进程帮我们去执行,然后将执行的结果放回给父进程打印出来。这就是这个实验的原理。

实验主要有三部分:

1.创建外部进程:

java中有两种方式:用ProcessBuilder类的start方法。用Runtime类的exec方法。本实验用的是前两种。

执行命令的时候,我们要向ProcessBuilder传递参数,第一个参数需要是程序名,如:/usr/bin/ls等。

我们看下面的代码:

ProcessBuilder pb = new ProcessBuilder();
ArrayList<String> param = new ArrayList<>();
param.add("/usr/bin/"+strs[i]);			//注意,前缀/usr/bin/。第一个参数需要类似/usr/bin/ls的,所以要拼接一下
param.add(...)		//...是要加入的参数
pb.command(param);	//添加参数

我们要实现的是输入命令ls,子进程去调用程序,返回结果回来。我们执行命令的程序都在/usr/bin中,所以要加统一的前缀。

2.更改目录:

因为要修改工作目录,所以调用ProcessBuilder directory(File Directory)方法来修改目录

3.添加历史记录特性

用一个ArrayList变量来记录历史命令即可。

具体java代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.io.File;

public class SimpleShell {
    public static void main(String[] args) throws IOException {
        String commandLine = null;
        Process pro = null;
        int flag = 0;
	    ArrayList<String> history = new ArrayList<>();	//保存指令历史
        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
        ProcessBuilder pb = new ProcessBuilder();
        while(true){
            if(flag == 0){   //如果标记为0,则正常执行;标记为1,则不用接收输入
                System.out.print("jsh>");
                commandLine = console.readLine().trim();    //删除前后空格
            }
            if(commandLine.equals("")){  //遇到空,继续
                continue;
            }
            if(commandLine.equals("exit")){  //退出
                return;
            }
	        
            ArrayList<String> param = new ArrayList<>();
            //param.add("/c");
            history.add(commandLine);	//保存指令
    	    if(commandLine.equals("cd")){	//若输入的命令是cd,切换到home目录下
        		pb.directory(new File(System.getProperty("user.dir")));
        		System.out.println(System.getProperty("user.dir"));
        		flag = 0;   //设置标记值
        		continue;
    	    }else if(commandLine.length()>2
                     &&commandLine.substring(0,2).equals("cd")
                     &&commandLine.charAt(2) == ' '){ //命令是cd dir 格式的
    	        String dirName = "";        //默认格式是 cd /home
    	        if(commandLine.length()>3&&commandLine.charAt(3) != '/'){   //若格式是cd test
    	            dirName = System.getProperty("user.dir")+"/";
    	        }
    	        pb.directory(new File(dirName+commandLine.substring(3)));
    	        System.out.println(dirName+commandLine.substring(3));
    	        flag = 0;   //设置标记值
                continue;
    	    }else if(commandLine.equals("history")){	//若是history指令,则输出历史
    	    	for(int i=0;i<history.size();i++){
        			System.out.println(i+" "+history.get(i));
        		}
        		flag = 0;   //设置标记值
        		continue;
    	    }else if(commandLine.equals("!!")){
    	    	if(history.size() == 1){
    			    System.out.println("no history command!");
    			    flag = 0;   //设置标记值
        		}else{
        			commandLine = history.get(history.size()-2);
        			flag = (flag == 1?0:1);   //设置标记值
        		}
        		continue;
    	    }else if(commandLine.charAt(0)=='!'){
    	    	//转换命令后的数字
        		String numStr = commandLine.substring(1);
        		int num = 0;
        		try {
                    num = Integer.parseInt(numStr);   
                } catch(Exception e) {
                    System.out.println("error:invaild param");
                    flag = 0;   //设置标记值
                    continue;
                }
        		if(num>=0 && num<(history.size()-1)){   //!后面的数字需要符合条件
        		    //将指令替换为历史指令
        		    commandLine = history.get(num);
        		    flag = (flag == 1?0:1);    //设置标记值
        		    continue;
        		}else{
                    flag = 0;       //设置标记值 		    
        		}
    	    }
    	    flag = 0;   //设置标记值
            String[] strs = commandLine.split(" ");
            //添加到参数中
            for(int i=0;i<strs.length;i++){
                if(i==0){
            		param.add("/usr/bin/"+strs[i]);
        		}else{
        			param.add(strs[i]);
        		}
            }  
    	    pb.command(param);	//添加参数
            pb.redirectErrorStream(true);   //合并正确流和错误流
            try {
                pro = pb.start();   
            } catch(IOException e) {
                System.out.println("error:invaild input");
                continue;
            }
            BufferedReader br = new BufferedReader(new InputStreamReader(pro.getInputStream()));
            // BufferedReader brError = new BufferedReader(new InputStreamReader(pro.getErrorStream()));
            String line;
            // if(brError.readLine() != null){     //子程序执行出错
            //     System.out.println("error:invaild input");
            //     brError.close();
            // }else{                              //输出子程序的结果
            while((line=br.readLine())!=null){
                System.out.println(line);
            }
            br.close();
            // }
        }
    }
}

结果展示:

image-20211207214226599

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值