Shell基础

Shell是一种脚本编程语言,作为用户与Linux内核之间的接口,提供高效的操作方式。它包括内置命令和外部命令,PATH变量决定了如何查找外部命令。Shell脚本允许用户编写自动化任务,通过函数传参方式处理命令选项和参数。在新进程中运行脚本会产生新的PID,而使用source命令则在当前Shell进程中执行,保持相同PID。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明: 本篇博客的学习途径主要为以下网站和课堂讲解,发博客目的仅为学习使用,在该博客的基础上做了一定程序的简略和修改。
参考博客 :
原文链接:http://c.biancheng.net/shell/

Shell基础

什么是Shell?

【总结】
Shell 既是一种脚本编程语言,也是一个连接内核和用户的软件。

Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。

  • Shell 是如何连接用户和内核的?

我们运行一个命令,大部分情况下 Shell 都会去调用内核暴露出来的接口,这就是在使用内核,只是这个过程被 Shell 隐藏了起来,它自己在背后默默进行,我们看不到而已。

  • Shell 还能连接其它程序?
    在 Shell 中输入的命令,
    • 有一部分是 Shell 本身自带的,这叫做内置命令;
    • 有一部分是其它的应用程序(一个程序就是一个命令),这叫做外部命令。

Shell 可以调用其他的程序,每个程序就是一个命令,这使得 Shell 命令的数量可以无限扩展,如文本或字符串检索、文件的查找或创建、大规模软件的自动部署、更改系统设置、监控服务器性能、发送报警邮件、抓取网页内容、压缩文件等。
Shell 还可以让多个外部程序发生连接,在它们之间很方便地传递数据,也就是把一个程序的输出结果传递给另一个程序作为输入

在这里插入图片描述

  • Shell 也支持编程

Shell 主要用来开发一些实用的、自动化的小工具,而不是用来开发具有复杂业务逻辑的中大型软件,例如检测计算机的硬件参数、搭建 Web 运行环境、日志分析等,Shell 都非常合适。

  • Shell 是一种脚本语言

Shell 就是一种脚本语言,我们编写完源码后不用编译,直接运行源码即可。

bash Shell

bash是最常用的Shell
bash shell 是 Linux 的默认 shell
Shell 是一个程序,一般都是放在/bin或者/usr/bin目录下,

当前 Linux 系统可用的 Shell 都记录在/etc/shells文件中。
/etc/shells是一个纯文本文件,你可以在图形界面下打开它,也可以使用 cat 命令查看它。

$ cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh

内置命令和外部命令

内置命令

最常用的命令才有理由成为内置命令,比如 cd、kill、echo 等;

[root@localhost ~]# type cd
cd is a Shell builtin
[root@localhost ~]# type ifconfig
ifconfig is /sbin/ifconfig

由此可见,cd 是一个 Shell 内建命令,而 ifconfig 是一个外部文件,它的位置是/sbin/ifconfig。

外部命令

【问题】一个外部的应用程序究竟是如何变成一个 Shell 命令的呢?

  • 应用程序就是一个文件,只不过这个文件是可以执行的,用户在 Shell 中输入一个外部命令后,只是将可执行文件的名字告诉了 Shell,但是并没有告诉 Shell 去哪里寻找这个文件。

【问题】Shell是如何找到这个文件的?

  • Shell 在启动文件中增加了一个叫做 PATH 的环境变量,该变量就保存了 Shell 对外部命令的查找路径,如果在这些路径下找不到同名的文件,Shell 也不会再去其它路径下查找了,它就直接报错。

我们使用 echo 命令输出 PATH 变量的值,看看它保存了哪些检索路径:

[mozhiyan@localhost ~]$ echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/mozhiyan/.local/bin:/home/mozhiyan/bin

不同的路径之间以:分隔。


由此 我们可以编写自己的Shell文件 或者 仿写bash命令
【举例】
编译名字为 getsum 的应用程序,并放在 ~ / bin目录(~ 表示用户主目录)下,然后在 Shell 中输入下面的命令,就可以计算 1+2+3 … +99+100 的值。

#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
    int start = 0;
    int end = 0;
    int sum = 0;
    int opt;
    char *optstring = ":s:e:";

    while((opt = getopt(argc, argv, optstring))!= -1){
        switch(opt){
            case 's': start = atoi(optarg); break;
            case 'e': end = atoi(optarg); break;
            case ':': puts("Missing parameter"); exit(1);
        }
    }
   
    if(start<0 || end<=start){
        puts("Parameter error"); exit(2);
    }
   
    for(int i=start; i<=end; i++){
        sum+=i;
    }
    printf("%d\n", sum);

    return 0;
}

-s选项表示起始数字,-e选项表示终止数字。

[mozhiyan@localhost ~]$ getsum -s 1 -e 100
5050

除了可以新增加Shell命令到/bin目录下,也可以改变PATH,让Bash搜索的时候搜索该目录
具体操作:
http://c.biancheng.net/view/vip_3233.html


Shell命令选项和参数的本质:函数传参

一个 Shell 内置命令就是一个内部的函数,一个外部命令就是一个应用程序

内置命令后面附带的所有数据(所有选项和参数)最终都以参数的形式传递给了函数
外部命令后面附带的所有数据(所有选项和参数)最终都以参数的形式传递给了应用程序。

不管是内置命令还是外部命令,它后面附带的数据最终都以参数的形式传递给了函数

getsum -s 1 -e 100要传递的四个参数分别是 -s、1、-e、100

减号-也会一起传递过去,在函数内部,减号-可以用来区分该参数是否是命令的选项
自己编写的外部命令getsum源码

#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
    int start = 0;
    int end = 0;
    int sum = 0;
    int opt;
    char *optstring = ":s:e:";

    //分析接收到的参数
    while((opt = getopt(argc, argv, optstring))!= -1){
        switch(opt){
            case 's': start = atoi(optarg); break;
            case 'e': end = atoi(optarg); break;
            case ':': puts("Missing parameter"); exit(1);
        }
    }
   
    //检测参数是否有效
    if(start<0 || end<=start){
        puts("Parameter error"); exit(2);
    }
   
    //打印接收到的参数
    printf("Received parameters: ");
    for(int i=0; i<argc; i++){
        printf("%s  ", argv[i]);
    }
    printf("\n");
   
    //计算累加的和
    for(int i=start; i<=end; i++){
        sum+=i;
    }
    printf("sum=%d\n", sum);

    return 0;
}

Shell命令提示符

[mozhiyan@localhost ~]$
- []是提示符的分隔符号,没有特殊含义。
- mozhiyan表示当前登录的用户,我现在使用的是 mozhiyan 用户登录。
- @是分隔符号,没有特殊含义。
- localhost表示当前系统的简写主机名(完整主机名是 localhost.localdomain)。
- ~代表用户当前所在的目录为主目录(home 目录)。如果用户当前位于主目录下的 bin 目录中,那么这里显示的就是bin。
- $是命令提示符。Linux 用这个符号标识登录的用户权限等级:如果是超级用户(root 用户),提示符就是#;如果是普通用户,提示符就是$。

第二层命令提示符

有些命令不能在一行内输入完成,需要换行,这个时候就会看到第二层命令提示符。
第二层命令提示符默认为>

  • echo 命令用来输出一个字符串。字符串是一组由" "包围起来的字符序列,echo 将第一个"作为字符串的开端,将第二个"作为字符串的结尾。
[mozhiyan@localhost ~]$ echo "Shell教程"
Shell教程
[mozhiyan@localhost ~]$ echo "
> http://
> c.biancheng.net
> "

http://
c.biancheng.net

第二个 echo 命令需要多行才能输入完成,提示符>用来告诉用户命令还没输入完成,请继续输入。

Shell脚本

【举例说明】
打开文本编辑器,新建一个文本文件,并命名为 test.sh。

扩展名sh代表 shell,扩展名并不影响脚本执行,见名知意就好

#!/bin/bash
echo "Hello World !"  #这是一条语句
  • 第 1 行的#!是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell;后面的/bin/bash就是指明了解释器的具体位置。
  • 第 2 行的 echo 命令用于向标准输出文件 输出文本

【举例说明】

#!/bin/bash
# Copyright (c) http://c.biancheng.net/shell/
echo "What is your name?"
read PERSON
echo "Hello, $PERSON"
  • 第 4 行中 read表示从终端读取用户输入的数据,并赋值给 PERSON 变量

read 命令用来从标准输入文件(Standard Input,stdin,一般就是指键盘)读取用户输入的数据。

  • 第 5 行中,echo表示输出变量 PERSON 的内容。注意在变量名前边要加上$,这样才能表示是值value,否则变量名会作为字符串的一部分处理。

执行Shell脚本(多种方法)

【总结】
如果需要在新进程中运行 Shell 脚本,可以使用bash test.sh这种写法;
如果在当前进程中运行 Shell 脚本,可以使用source test.sh这种写法。


在新进程中运行 Shell 脚本

在新进程中运行 Shell 脚本有多种方法。

  • 方法一 : 将 Shell 脚本作为程序运行

Shell 脚本也是一种解释执行的程序,可以在终端直接调用(需要使用 chmod 命令给 Shell 脚本加上执行权限)

[mozhiyan@localhost ~]$ cd demo                #切换到 test.sh 所在的目录
[mozhiyan@localhost demo]$ chmod +x ./test.sh  #给脚本添加执行权限
[mozhiyan@localhost demo]$ ./test.sh           #执行脚本文件
Hello World !                                  #运行结果


  • 方法二 : 将 Shell 脚本作为参数传递给 Bash 解释器

直接运行 Bash 解释器,将脚本文件的名字作为参数传递给 Bash
(通过这种方式运行脚本,不需要在脚本文件的第一行指定解释器信息,写了也没用。)

[mozhiyan@localhost ~]$ cd demo               #切换到 test.sh 所在的目录
[mozhiyan@localhost demo]$ /bin/bash test.sh  #使用Bash的绝对路径
Hello World !                                 #运行结果

更加简洁的写法是运行 bash 命令

bash 是一个外部命令,Shell 会在 /bin 目录中找到对应的应用程序,也即 /bin/bash

[mozhiyan@localhost ~]$ cd demo
[mozhiyan@localhost demo]$ bash test.sh
Hello World !

检测是否开启了新进程

Linux 中的每一个进程都有一个唯一的 ID,称为 PID,$$是 Shell 中的特殊变量

使用$$变量就可以获取当前进程的 PID。
#!/bin/bash
echo $$  #输出当前进程PID

使用以上两种方式来运行 check.sh,观察到PID不一样,所以判定为两个进程

[mozhiyan@localhost demo]$ echo $$
2861  #当前进程的PID
[mozhiyan@localhost demo]$ chmod +x ./check.sh
[mozhiyan@localhost demo]$ ./check.sh
4597  #新进程的PID
[mozhiyan@localhost demo]$ echo $$
2861  #当前进程的PID
[mozhiyan@localhost demo]$ /bin/bash check.sh
4584  #新进程的PID

在当前进程中运行 Shell 脚本

source 命令

source 是 Shell 内置命令的一种,它会读取脚本文件中的代码,并依次执行所有语句
你也可以理解为,source 命令会强制执行脚本文件中的全部命令,而忽略脚本文件的权限。

source 命令的用法为:

source filename

简写为 (注意点号.和文件名中间有一个空格。)

. filename

【举例】使用 source 运行上节的 test.sh:
这四种写法均可

[mozhiyan@localhost ~]$ cd demo              #切换到test.sh所在的目录
[mozhiyan@localhost demo]$ source ./test.sh  #使用source
Hello World !
[mozhiyan@localhost demo]$ source test.sh    #使用source
Hello World !
[mozhiyan@localhost demo]$ . ./test.sh       #使用点号
Hello World !
[mozhiyan@localhost demo]$ . test.sh         #使用点号
Hello World !

【对比】:使用 source 命令不用给脚本增加执行权限,并且写不写./都行。


检测是否在当前 Shell 进程中

仍然借助$$变量来输出进程的 PID

[mozhiyan@localhost ~]$ cd demo
[mozhiyan@localhost demo]$ echo $$
5169  #当前进程PID
[mozhiyan@localhost demo]$ source ./check.sh
5169  #Shell脚本所在进程PID
[mozhiyan@localhost demo]$ echo $$
5169  #当前进程PID
[mozhiyan@localhost demo]$ . ./check.sh
5169  #Shell脚本所在进程PID

进程的 PID 都是一样的,当然是同一个进程了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值