Shell脚本语言

shell 是一个编程语言解释器,这个解释器解释从键盘输入的命令,也解释存储在脚本中的命令序列。

shell 脚本是一个包含一系列命令的文件。运行一个脚本就是运行这个文件中的每个命令。可以用一个 shell 脚本在一次请求中来执行多个命令。

1.sh 的编程特征:变量、 1/0 和 if.. then
shell 脚本是真正的程序。

脚本中除了命令之外还包括以下元素。
(1)变量
脚本中可以定义变量。在定义之后使用了它们,用前辍$来取得变量的值。变量名不一定要大写,只是习惯上将其大写。
(2) 用户输入
read 命令告诉 shell 要从标准输入中读入一个字符串。可以使用 read 来创建交互的脚本,也可以从文件或管道中读入数据。
(3) 控制
这个脚本包括了 if. .then. . else. .fi 控制语句。其他的脚本控制语句还有 while 、 case和for

(4) 环境
脚本使用一个名为 HOME 的变量。 HOME 的值是你的主目录的路径。 HOME 变量是由 login 程序设置的,可以被 login 进程的所有子进程使用。 HOME 变量是多个环境变量(environment variables) 中的一个。这些环境变量记录了个性化设置。而这些设置能影响很多程序的行为。比如, TZ 变量记录了当前的时区。将 TZ 设置为 "EST5EDT" 是告诉那些使用ctime 的程序,比如 date 或 1 日一 1 ,应该显示美国东部时间。

smsh.h

#include<stdio.h>
#define YES 1
#define NO 0
char * next_cmd(char *,FILE *);
char ** splitline(char *);
void freelist(char **);
void * emalloc(size_t);
void *erealloc(void *,size_t);
int execute(char **);
void fatal(char *,char *,int);
smsh1.c

#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include"smsh.h"
#define DFL_PROMPT  ">"

int main()
{
  char * cmdline,*prompt,**arglist;
  int result;
  void setup();

  prompt = (char *)DFL_PROMPT;
  setup();

  while((cmdline = next_cmd(prompt,stdin))!=NULL)//输入NULL退出shell
  {
    if((arglist = splitline(cmdline))!=NULL)
    {
      result = execute(arglist);
      freelist(arglist);
    }
    free(cmdline);
  }
  return 0;
}

void setup()
{
  signal(SIGINT,SIG_IGN);
  signal(SIGQUIT,SIG_IGN);
}

void fatal(char *s1,char *s2,int n)
{
  fprintf(stderr,"Error:%s,%s\n",s1,s2);
  exit(n);
}
splitline.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"smsh.h"

char * next_cmd(char *prompt,FILE *fp)//从输入流中读入下一个命令,调用malloc来分配内存以接受任意长度的命令行。碰到文件结束符,返回NULL
{
  char *buf = NULL;
  int bufspace = 0;
  int pos = 0;//已经接受的字符个数
  int c;
  printf("%s",prompt);
  while((c = getc(fp))!=EOF)//从标准输入一个一个接受字符
  {
    if(pos +1 >= bufspace)//接收到字符是否大于分配的内存
    {
      if(bufspace == 0)
        buf = (char *)emalloc(BUFSIZ);//BUFSIZ == 8192
      else
        buf = (char *)erealloc(buf,(size_t)bufspace+BUFSIZ);//realloc(buf,bufspace+BUFSIZE);
      bufspace += BUFSIZ;
    }
    if(c == '\n')
        break;
    buf[pos++] = (char)c;
  }
  if(c == EOF && pos == 0)//判断是否输入结束标志或者没输入
    return NULL;
  buf[pos] = '\0';
  return buf;
}

#define is_delim(x) ((x) == ' '||(x) == '\t')
char ** splitline(char *line)
{
  char *newstr(char *,int);
  char ** args = NULL;
  int spots = 0;//已分配的内存
  int bufspace = 0;
  int argnum = 0;
  char *cp = line;//命令
  char *start;
  int len;
  if(line == NULL)//判断输入命令是否为空
    return NULL;
  args = (char **)emalloc(BUFSIZ);
  bufspace = BUFSIZ;
  spots = BUFSIZ/sizeof(char *);//多少个char *
  while(*cp!='\0')//判断输入命令格式 讲命令和参数分离
  {
    while(is_delim(*cp))//cp指向命令第一个字符
      cp++;
    if(*cp == '\0')
      break;
    if(argnum + 1 >= spots)//命令和参数的个数是否大于分配的内存
    {
      *args = (char *)erealloc(args,(size_t)bufspace+BUFSIZ);
      bufspace += BUFSIZ;
      spots += (BUFSIZ/sizeof(char *));
    }
    start = cp;//命令或者参数
    len = 1;
    while(*++cp!='\0'&&!(is_delim(*cp)))//命令的长度
      len++;//命令、参数长度
    args[argnum++] = newstr(start,len);
  }
  args[argnum]= NULL;
  return args;
}
char * newstr(char *s,int l)
{
  char *rv = (char *)emalloc((size_t)l+1);
  rv[l] = '\0';
  strncpy(rv,s,(size_t)l);//将命令拷贝到rv
  return rv;
}
void freelist(char ** list)
{
  char ** cp = list;
  while(*cp)//释放一级指针指向的空间
    free(*cp++);
  free(list);
}
void * emalloc(size_t n)
{
  void *rv;
  if((rv = malloc(n)) == NULL)
    fatal((char *)("out of memory"),(char*)(""),1);
  return rv;
}
void * erealloc(void *p,size_t n)
{
  void * rv;
  if((rv = realloc(p,n)) == NULL)
    fatal((char *)("realloc() failed"),(char *)(" "),1);
  return rv;
}

execute.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>

int execute(char *argv[])
{
  int pid;
  int child_info = -1;
  if(argv[0] == NULL)
    return 0;
  if((pid = fork()) == -1)
    perror("fork");
  else if(pid == 0)
  {//子进程执行 命令
    signal(SIGINT,SIG_DFL);//默认处理方式
    signal(SIGQUIT,SIG_DFL);
    execvp(argv[0],argv);//执行成功的话要执行的命令程序会退出
    perror("cannot execut command");//执行失败报错
    exit(1);
  }
  else
  {
    if(wait(&child_info) == -1)//等待子进程执行命令并退出
      perror("wait");
  }
    return child_info;
}
Makefile
smsh1:smsh1.c splitline.c execute.c
	gcc $^ -o $@ -g



diff命令用来比较两个文本文件,如果两个文件相同,diff返回0以表明成功。shell中以exit(0)表示成功。

shell命令中如果 if 后的条件是一系列的命令,那么最后一个命令的 exit 值被用作这个语句块的条件值,并由此来决定条件是否成立。

环境:

  环境是每个程序都可以存取的→个字符串数组。每个数组中的字符串都以 var=value 这样的形式出现,数组的地址被存放在一个名为 envlron 的全局变量里。环境就是 envlron 指向的字符串数组,读环境就是读这个字符串数组,改变环境就是改变字符串、改变这个数组中的指针或者将这个全局指针指向其他数组。


exec清除所有数据:

exec 的调用就像换脑,用目标程序的代码和数据替换调用程序的代码和数据。但是 envlron 指针指向的数组是惟一的例外,当内核执行系统调用
execve 时,它将数组和字符串复制到新的程序的数据空间, 子程序中环境的设置是父进程环境的复本,子进程不能修改父进程的环境。因为在进
程调用 fork 和 exec 时整个环境都被自动的复制了,所以通过环境来传递数据比较方便、
快捷。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值