计算机中shell是干什么的

参考文章Shell 是用来解决什么问题的?
可以把 shell 理解为 命令解释器,用来解决用户如何与操作系统通信的问题(进行系统调用)。
操作系统对外提供的接口是“系统调用”,也就是一堆编程用的接口。这些接口一般以C函数的形式暴露给使用者。通过这些接口,开发者可以命令操作系统“启动一个进程”,“查找某个目录下的所有文件”,“将某个文件的权限配置为744”等等。

实际上我们平时编程用的是对系统调用的包装,比如libc里的那些库函数。但无论如何,你总是得写代码才能使用它们。

为了不用使用电脑时每次都编写程序,再编译,再运行才能得到结果这么麻烦,就先写好程序,作为文件保存,然后弄个交互的界面,只要使用者敲一组字符串,就可以调用之前写好的程序文件完成工作。比如我们会在命令行里输入“ls -Rl”这种字符串。这个字符串被翻译成“ls”,“-R”,“-l”。“ls”帮我们找到那个之前写好的程序文件,并启动它;“-R”和“-l”被作为参数传给这个程序,告诉程序走“递归所有子目录”+“输出长格式”这部分代码。

这里输入的字符串通常包括了程序文件的名字(当然有例外,比如 Linux 的 alias 命令,比如 通过链接文件访问源文件),所以通常文件名就成了命令。

在 Linux 的 /bin 目录和 /usr/bin 目录中有 Linux 命令对应的文件,在 Windows 的 %windir% 目录即 操作系统安装硬盘分区的 Windows 目录 和 %windir%\system32 目录中有 Windows 命令对应的文件, 此外还可以引入外部命令和自定义命令。

这个负责把用户输入的字符串转换到需要执行的程序,并把结果以某个形式画出来的东西,就叫做“Shell”
在Linux中,bash负责按照某种格式把用户的输出的字符串翻译,比如对于普通非空字符翻译为程序和参数,并尝试去PATH里找对应的程序文件;对“空格”翻译成分隔符;对“$XXX”尝试进行环境变量的替换;对“|”翻译为管道;对 “>”翻译为输出重定向;对一个指令末尾的“&”翻译为将程序转到后台执行……

另一方面终端将stdout、stderr输出的东西画成我们可以看的一坨坨字符,包括字符、字体、颜色、换行、甚至响铃。

对于图形化 shell 是通过鼠标的点击来访问文件的,但实际也是通过文件名,因为每个文件都有包含文件名的完整路径。

Shell(壳)kernel(核)
Linux命令行形式的:bash 、sh 、csh 、ksh
图形化的:KDE、GNOME、CDE、 XFCE
kernel
Windows命令行形式的:command,cmd.exe,Windows PowerShell
图形化的:Windows Explorer
DOS(windows 95)
Windows NT (Windows New Technology)
(Winidows XP开始使用)

【bash】 + 【终端】大概可以理解为一个以字符为交互方式的“Shell”。
在这里插入图片描述
一个更具体的例子:
在Linux终端中输入“ll”命令,Shell解析了ll,用alias翻译成了ls命令,然后执行对应代码,发起系统调用readdir,并把结果输出在终端上”。
ll是"ls -lh"的alias(输入"alias ll"可以看到)。ls的命令实现在coreutlis包里。这里有对应的源代码:http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c
在2900多行有发起对readdir的调用。用"man readdir"可以看到对这个系统调用的解释。
这里应该明确下发起系统调用readdir的不是Shell自己,而是被Shell执行的ls命令
Shell本身说白了就是个无脑 while fork 循环……

static void
print_dir (char const *name, char const *realname, bool command_line_arg)
{
  DIR *dirp;
  struct dirent *next;
  uintmax_t total_blocks = 0;
  static bool first = true;

  errno = 0;
  dirp = opendir (name);
  if (!dirp)
    {
      file_failure (command_line_arg, _("cannot open directory %s"), name);
      return;
    }

  if (LOOP_DETECT)
    {
      struct stat dir_stat;
      int fd = dirfd (dirp);

      /* If dirfd failed, endure the overhead of stat'ing by path  */
      if ((0 <= fd
           ? fstat_for_ino (fd, &dir_stat)
           : stat_for_ino (name, &dir_stat)) < 0)
        {
          file_failure (command_line_arg,
                        _("cannot determine device and inode of %s"), name);
          closedir (dirp);
          return;
        }

      /* If we've already visited this dev/inode pair, warn that
         we've found a loop, and do not process this directory.  */
      if (visit_dir (dir_stat.st_dev, dir_stat.st_ino))
        {
          error (0, 0, _("%s: not listing already-listed directory"),
                 quotef (name));
          closedir (dirp);
          set_exit_status (true);
          return;
        }

      dev_ino_push (dir_stat.st_dev, dir_stat.st_ino);
    }

  clear_files ();

  if (recursive || print_dir_name)
    {
      if (!first)
        DIRED_PUTCHAR ('\n');
      first = false;
      DIRED_INDENT ();

      char *absolute_name = NULL;
      if (print_hyperlink)
        {
          absolute_name = canonicalize_filename_mode (name, CAN_MISSING);
          if (! absolute_name)
            file_failure (command_line_arg,
                          _("error canonicalizing %s"), name);
        }
      quote_name (realname ? realname : name, dirname_quoting_options, -1,
                  NULL, true, &subdired_obstack, absolute_name);

      free (absolute_name);

      DIRED_FPUTS_LITERAL (":\n", stdout);
    }

  /* Read the directory entries, and insert the subfiles into the 'cwd_file'
     table.  */

  while (1)
    {
      /* Set errno to zero so we can distinguish between a readdir failure
         and when readdir simply finds that there are no more entries.  */
      errno = 0;
      next = readdir (dirp);//注意 这里使用了readdir 系统调用
      if (next)
        {
          if (! file_ignored (next->d_name))
            {
              enum filetype type = unknown;

#if HAVE_STRUCT_DIRENT_D_TYPE
              switch (next->d_type)
                {
                case DT_BLK:  type = blockdev;		break;
                case DT_CHR:  type = chardev;		break;
                case DT_DIR:  type = directory;		break;
                case DT_FIFO: type = fifo;		break;
                case DT_LNK:  type = symbolic_link;	break;
                case DT_REG:  type = normal;		break;
                case DT_SOCK: type = sock;		break;
# ifdef DT_WHT
                case DT_WHT:  type = whiteout;		break;
# endif
                }
#endif
              total_blocks += gobble_file (next->d_name, type,
                                           RELIABLE_D_INO (next),
                                           false, name);

              /* In this narrow case, print out each name right away, so
                 ls uses constant memory while processing the entries of
                 this directory.  Useful when there are many (millions)
                 of entries in a directory.  */
              if (format == one_per_line && sort_type == sort_none
                      && !print_block_size && !recursive)
                {
                  /* We must call sort_files in spite of
                     "sort_type == sort_none" for its initialization
                     of the sorted_file vector.  */
                  sort_files ();
                  print_current_files ();
                  clear_files ();
                }
            }
        }
      else if (errno != 0)
        {
          file_failure (command_line_arg, _("reading directory %s"), name);
          if (errno != EOVERFLOW)
            break;
        }
      else
        break;

      /* When processing a very large directory, and since we've inhibited
         interrupts, this loop would take so long that ls would be annoyingly
         uninterruptible.  This ensures that it handles signals promptly.  */
      process_signals ();
    }

  if (closedir (dirp) != 0)
    {
      file_failure (command_line_arg, _("closing directory %s"), name);
      /* Don't return; print whatever we got.  */
    }

  /* Sort the directory contents.  */
  sort_files ();

  /* If any member files are subdirectories, perhaps they should have their
     contents listed rather than being mentioned here as files.  */

  if (recursive)
    extract_dirs_from_files (name, false);

  if (format == long_format || print_block_size)
    {
      char const *p;
      char buf[LONGEST_HUMAN_READABLE + 1];

      DIRED_INDENT ();
      p = _("total");
      DIRED_FPUTS (p, stdout, strlen (p));
      DIRED_PUTCHAR (' ');
      p = human_readable (total_blocks, buf, human_output_opts,
                          ST_NBLOCKSIZE, output_block_size);
      DIRED_FPUTS (p, stdout, strlen (p));
      DIRED_PUTCHAR ('\n');
    }

  if (cwd_n_used)
    print_current_files ();
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值