二、shell

1、shell作用:(1)打出提示符,获取用户输入的指令;(2)解析命令,分解命令及参数,处理字符‘|’管道,‘&’后台,‘>’,‘<’;(3)寻找命令文件,对照PATH中‘:’隔开的路径寻找。(4)执行命令

//(1)打出提示符,获取用户输入的指令
char *path;
path = get_current_dir_name();
printf("%s>$",path);

lc_char = getchar();
while(lc_char != '\n' )
{
    buffer[size++] = lc_char;
    lc_char = getchar();
}
buffer[size]='\0';

input = (char *)malloc(sizeof(char) * (size+1));
strcpy(input, buffer); 
} 

//(2)解析命令
int i,j=0;
for(i=0;j<size;i++)
{
    //从定向处理 
    if(input[i]=='<' || input[i]=='>')
        **redirect(input, size);**
    //管道处理 
    else if(input[i]=='|') 
        **pipel(input, size);**

    if(input[i]==' ', || input[i]=='\t', || input[i]== '\0')
    {
        //处理连续空格和tab 
        if(j==0)
            continue;

        //根据空格把多个参数分散存在 *arg中 
        else
        {
            buffer[j++]='\0';
            arg[k] = (char *)malloc(sizeof(char) * j);
            strcpy(arg[k],buffer);

            j=0;
            k++;
        }
    } 

    else
    {
        //标记后台运行 
        if(input[i]=='&' && input[i+1]=='\0')
        {
            is_back =1;
            continue;
        }
        buffer[j++]=input;
    } 
} 
//(4)执行命令
if((pid = fork())==0)
    exec(buffer, arg);
else
    if(is_back == 0)//新进程不在后台运行,父进程必须等起结束 
        waitpid(pid, &status, 0); 

    //返回父进程是释放申请的空间
     for(i=0;i<k;i++)
        free(arg[i]);

2、新进程会继承父进程的文件描述符,这就是为什么并发进程会读写同一个键盘和显示器。
重定向实现:

//重定向       
if(in[i]=='<')
    ls_in=1;
if(in[i]=='>')
    is_out=1; 

if(ls_in)
{
    fd_in=open(filename[is_in], O_RONLY, S_IRUSR|S_IWUSR);
    dup2(fd_in, STDIN_FILENO);//把fd_in所指向的文件描述符复制到 STDIN_FILENO,STDIN_FILENO已打开则先关闭 
}
if(ls_OUT)
{
    fd_out=open(filename[is_out], O_WRONLY|O_CREATE|O_TRUNC, S_IRUSR|S_IWUSR);
    dup2(fd_out, STDOUT_FILENO);
}

3、普通管道,子进程可以通过类型继承打开文件描述符的方式继承管道。而命名管道,进程通过使用和管道连接的类似文件名的字符串获得管道。当进程使用命名管道,该管道就成了系统资源。

//命令中管道实现
int fd[2];

if((child1 = fork())==0)
{
    close(fd[0]);//关闭读端
    //将标准输出重定向到管道的写端,这样子进程的输出就写入了管道 
    dup2(fd[1],STDOUT_FILENO); 
    close(fd[1]);

    execv(buffer, argv[0]);
} 
else{
    //父进程等待写入管道的进程结束
    waitpid(child1, &li_comm, 0);
    //管道以字节流的形式读入读出,我们可以写入一个结束标记,告诉读进程数据到这就结束了
    end[0]=0x1a;
    write(fd[1],end,1);
    close(fd[1]); 
}

if((child2 = fork())==0)
{
    //将标准输入重定向到管道的读端
    dup2(fd[0],STDIN_FILENO); 
    close(fd[0]);

    execv(buffer, argv[1]);
} 

4、shell变量

首行指明使用哪种shell
#!/bin/bash

只读变量,字符串可以用单引号,也可以用双引号,也可以不用引号
str="http://www.w3cschool.cc"
readonly str

删除变量,只读变量不能删除
unset str1

用单引号,不进行转义或取变量
echo '$name\"'
$name\"

双引号里面可以有变量和转义字符
your_name='qinjx'
str="Hello, I know your are \"$your_name\"! \n"
echo $str
$Hello, I know your are "qinjx"! \n

获取字符串长度
echo ${#string} 

提取子字符串,从字符串第 2 个字符开始截取 4 个字符
echo ${string:1:4}

查找子字符串,查找字符 "i 或 s" 的位置,下面为反引号:
echo `expr index "$string" is` 

$# 传递到脚本的参数个数
$*	以"$1 $2$n"的形式输出所有参数
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误

Shell 数组用括号来表示,元素用"空格"符号分割开
array_name=(value1 ... valuen)

获取数组中的所有元素
 ${my_array[*]}
 ${my_array[@]}

获取数组的长度
 ${my_array[#*]}
 ${my_array[#@]}

$* 与 $@ 区别:
相同点:都是引用所有参数。
不同点:合成单个参数,多个参数

5、shell运算

原生bash不支持简单的数学运算,expr 是一款表达式计算工具,使用它能完成表达式的求值操作
计算2+22和‘+’之间要有空格
val=`expr 2 + 2`

条件表达式要放在方括号之间,并且要有空格
例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。

乘号(*)前边必须加反斜杠(\)才能实现乘法运算
val=`expr $a \* $b`

a<20 || b>100
-o  或运算, [ $a -lt 20 -o $b -gt 100 ] 
-a  与运算

-z  检测字符串长度是否为0,为0返回 true。  [ -z $a ] 返回 false。
-n  检测字符串长度是否为0,不为0返回 true。 [ -n $a ] 返回 true。
str 检测字符串是否为空,不为空返回 true。   [ $a ] 返回 true。

开启转义 -e,(-e 文件名 如果文件存在则为真)
echo -e "OK! \n" 
echo "It it a test"
$
OK! 
It it a test

printf不会像 echo 自动添加换行符,我们可以手动添加 \n
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg  
-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐)
%6.2f后,小数部分为两位,总长度6位,前面补空格
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值