news 2026/5/16 17:21:34

一、shell介绍

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一、shell介绍

一、shell介绍

1.1 shell起源

  • 1964年,美国AT&T公司的贝尔实验室、麻省理工学院及美国通用电气公司共同参与开始研发一套可以安装在大型主机上的多用户、多任务的操作系统,该操作系统的名称为Multics。

  • 1970年,丹尼斯•里奇和汤普逊启动了另外一个新的多用户、多任务的操作系统的项目,他们把这个项目称之为UNICS。

  • 1973年,使用C语言重写编写了Unix。通过这次编写,使得Unix得以移植到其他的小型机上面。

  • 1979年,第一个重要的标准UNIX Shell在Unix的第7版中推出,并以作者史蒂夫•伯恩(StephenBourne)的名字命名,叫做Bourne Shell,简称为sh。

  • 20世纪70年代末,C Shell作为2BSD UNIX的一部分发布,简称csh。之后又出现了许多其他的Shell程序,主要包括Tenex C Shell(tcsh)、Korn Shell(ksh)以及GNU Bourne-Again shell(bash)。

查看当前系统支持的shell:

[root@server ~]# cat /etc/shells/bin/sh /bin/bash /usr/bin/sh /usr/bin/bash

查看当前系统默认shell

[root@server ~]# echo $SHELL/bin/bash

1.2 shell是什么

1.2.1 shell是命令解释器

shell(壳)能识别用户输入的各种命令,并传递给操作系统。

真正能够控制计算机硬件(CPU、内存、显示器等)的只有操作系统内核(Kernel),图形界面和命令行只是架设在用户和内核之间的一座桥梁,由于安全、复杂、繁琐等原因,用户不能直接接触内核(也没有必要),需要另外再开发一个程序,让用户直接使用这个程序;该程序的作用就是接收用户的操作(点击图标、输入命令),并进行简单的处理,然后再传递给内核,这样用户就能间接地使用操作系统内核。

用户界面和命令行就是这个另外开发的程序,就是这层“代理”。在Linux下,这个命令行程序叫做 Shell,Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。

Shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,它和 QQ、迅雷、Firefox 等其它软件没有什么区别。然而 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用 Linux。

1.2.2 shell是脚本语言

如果有一系列经常需要使用的shell命令,可以将其存储在一个文件里,shell可以读取这个文件并顺序执行其中的命令,我们把这样的文件就叫shell脚本。

编程语言 C/C++、java、Go语言等,必须在程序运行之前将所有代码都翻译成二进制形式,也就是生成可执行文件,用户拿到的是最终生成的可执行文件在计算机中运行。而shell是一门解释性语言,shell脚本不需要编译即可执行,即直接运行源码。

编译型语言的优点是执行速度快、对硬件要求低、保密性好,适合开发操作系统、大型应用程序、数据库等。

脚本语言的优点是使用灵活、部署容易、跨平台性好,非常适合 Web 开发以及小工具的制作。

shell脚本的优势在于处理操作系统底层的业务,因为有大量的linux系统命令为它做支撑。2000多个命令都是shell脚本编程的有力支撑,特别是grep、awk、sed等。

1.3 脚本的书写规范与执行

1.3.1脚本的书写规范

  • 脚本文件的名称:建议脚本文件名以.sh结尾,见名知意

  • 第一行声明:#!/bin/bash

  • 注释:其余以#开头的行表示注释

    • 尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰。

    • 单行注释,可以放在代码行的尾部或代码行的上部。

    • 多行注释,用于注解复杂的功能说明,可以放在程序体中,也可以放在代码块的开始部分。

      多行注释写法:使用冒号“:”配合here document,语法如下:xxxx 可以是字符或数字,单引号可以不加,但以防出现莫名其妙的意外发生,比如发生字符扩展、命令替换。

      :<<'xxxx' comment1 comment2 comment3 …… xxxx

    自动生成脚本开头的注释和说明:通过给root账号配置vim的“个性化默认设置”,使用root用户vim编辑创建.sh文件时会自动生成下面的关于脚本文件的注释说明。

    [root@server ~]# vim /root/.vimrcautocmd BufNewFile *.py,*.cc,*.sh,*.javaexec":call SetTitle()"func SetTitle()ifexpand("%:e")=='sh'call setline(1,"#!/bin/bash")call setline(2,"#########################")call setline(3,"#File name:".expand("%"))call setline(4,"#Version:v1.0")call setline(5,"#Email:admin@test.com")call setline(6,"#Created time:".strftime("%F %T"))call setline(7,"#Description:")call setline(8,"#########################")call setline(9,"")endif endfunc
  • 脚本中的语句:定义函数,定义变量并赋值,shell命令,流程控制语句等

    脚本执行后,打印内容到屏幕:

    • echo

      [root@server ~]# echo hello worldhello world#-n不打印换行[root@server ~]# echo -n hello worldhello world[root@server ~]##-e启用转义字符;格式:echo -e "\e[字体控制;字体颜色或背景色 字符串内容 \e[0m"#\e[表示控制开始,\e[0m表示控制结束#字体控制选项:1表示高亮,4表示下划线,5颜色闪烁#字颜色:30-37 , 背景色:40-47[root@server ~]# echo -e "\e[1;31m红色字\e[0m"红色字[root@server ~]# echo -e "\e[4;45;37m 紫底白字\e[0m"紫底白字
    • printf

      #需要自己添加换行\n[root@server ~]# printf "hello world"hello world[root@server ~]# printf "hello world\n"hello world#使用格式替代符打印[root@server ~]# printf "%d %s\n" 1 "abc"1abc[root@server ~]# printf "%10s %-3d %-4.2f\n" "zhangsan" 9 130.23 "lisi" 10 130.5zhangsan9130.23lisi10130.50# %s %d %f 都是格式替代符,%s 输出一个字符串,%d 整型输出,%f 输出实数,以小数形式输出。#%10s 字符串占10个字符宽度(- 表示左对齐,没有则表示右对齐),如果不足则自动以空格填充,超过也会将内容全部显示出来。#%-3d 数字占3个宽度(- 表示左对齐,没有则表示右对齐)# %-4.2f 格式化为小数,其中 .2 指保留2位小数

    脚本中一般是一行一条命令,而且是按照顺序执行每条命令。

    可以用以下符号在一行连接多条命令:;&&|||

    #先执行分号前的date命令再执行分号后面的命令[root@server ~]# date ; ls -l /etc/passwd#先执行&&符号前面的命令,如果前面命令执行成功则执行&&后面的命令;如果前面命令执行失败、报错,则不执行后面的命令[root@server ~]# mkdir /mnt/iso && mount /dev/sr0 /mnt/iso#先执行||符号前面的命令,如果前面命令执行成功则不执行后面的命令;如果前面命令执行失败、报错,则执行后面的命令[root@server ~]# mkdir tt || ls /#管道符|:管道左边的命令的输出作为管道右边命令的输入#例如显示剩余内存大小[root@server ~]# free -h | grep Mem | tr -s " " | cut -d " " -f4[root@server ~]# free -h | awk '/Mem/ {print $4}' # 使用awk截取第4列

[!Note]

shell中没有强制要求缩进,但是建议缩进,可以提高阅读性,程序更有层次感。

1.3.2执行shell脚本

  • 输入脚本文件的路径(绝对路径或者相对路径都可)执行脚本文件:需要x执行权限
  • bash 脚本文件
  • source 脚本文件
  • . 脚本文件

[!NOTE]

前两种方法都是启动一个子shell,在子shell中执行此脚本,脚本中设置的变量在脚本执行完毕后不会保存。

后两种方法是在当前shell进程中执行此脚本,而不是重新启动一个shell 在子shell进程中执行此脚本,并且脚本中设置的变量在脚本执行完毕后会保存下来。

#使用绝对路径或者相对路径方式执行脚本需要x执行权限[root@server ~]# mkdir /shell[root@server ~]# vim /shell/test.sh#!/bin/bashecho"hello world"[root@server ~]# /shell/test.sh-bash: /shell/test.sh: 权限不够[root@server ~]# cd /shell/[root@server shell]# ./test.sh-bash: ./test.sh: 权限不够[root@server shell]# bash /shell/test.shhello world[root@server shell]# source /shell/test.shhello world[root@server shell]# . /shell/test.shhello world[root@server shell]# chmod a+x /shell/test.sh[root@server shell]# /shell/test.shhello world[root@server shell]# ./test.shhello world
#前两种方式会产生子shell,脚本中的语句只在子shell中有效,当前shell中无效[root@server shell]# vim /shell/test1.sh#!/bin/bashcd/etc#执行脚本后,当前shell的工作目录未发生任何变化,因为只是在子shell中执行了语句,不会影响当前shell[root@server shell]# chmod a+x /shell/test1.sh[root@server shell]# /shell/test1.sh[root@server shell]# bash /shell/test1.sh#source和.执行方式脚本中的语句会在当前shell中生效[root@server shell]# source /shell/test1.sh#可以看到执行完脚本后工作目录发生了变化[root@server etc]#[root@server etc]# cd /shell/[root@server shell]# . /shell/test1.sh[root@server etc]#

1.3.3脚本的退出状态码

  • linux的命令执行后就会有一个退出状态码,可使用echo $?查看命令的退出状态码;

  • 退出状态码范围:0-255,通常情况下,执行成功的命令返回0,不成功的命令返回非0值;

  • 脚本执行完毕后的退出状态码取决于脚本的最后一条命令,也可以使用exit 0-255指定脚本的退出状态码,可使用echo $?查看脚本的退出状态码;

  • 函数也可以返回一个退出状态码,使用return 0-255返回函数的状态码,可使用echo $?查看函数的退出状态码。

#命令执行后的状态码[root@server ~]# echo "hello world"hello world[root@server ~]# echo $?0[root@server ~]# ls /root/hahahals: 无法访问'/root/hahaha':没有那个文件或目录[root@server ~]# echo $?2#脚本执行后的状态码[root@server ~]# vim /shell/test.sh#!/bin/bashecho"hello world"[root@server ~]# bash /shell/test.shhello world[root@server ~]# echo $?0[root@server ~]# vim /shell/test.sh#!/bin/bashecho"hello world"ls/root/hahaha[root@server ~]# bash /shell/test.shhello world ls: 无法访问'/root/hahaha':没有那个文件或目录[root@server ~]# echo $?2[root@server ~]# vim /shell/test.sh#!/bin/bashecho"hello world"ls/root/hahahaexit1[root@server ~]# bash /shell/test.shhello world ls: 无法访问'/root/hahaha':没有那个文件或目录[root@server ~]# echo $?1

[!note]

常见状态码:

0----------------命令运行成功1----------------通知未知错误2----------------误用shell命令126--------------命令不可执行127--------------没有找到命令128--------------无效退出参数128+x------------linux信号x的严重错误130--------------命令通过Ctrl+C终止255--------------退出状态码越界
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/16 17:20:54

Go语言结构化错误处理实践:xerrors/Yuxi库的设计与应用

1. 项目概述&#xff1a;一个面向未来的Go语言错误处理库在Go语言的开发世界里&#xff0c;错误处理一直是个既基础又充满争议的话题。从经典的if err ! nil模式&#xff0c;到社区中不断涌现的各种包装、堆栈追踪方案&#xff0c;开发者们一直在寻找一种既简洁又强大的错误处理…

作者头像 李华
网站建设 2026/5/16 17:19:57

写代码像开挂:IT人的超能力技能树技术文章大纲

引言类比游戏中的“开挂”与高效编程的共通性提出“技能树”概念&#xff1a;通过系统化学习提升开发效率目标读者&#xff1a;初级到中级的开发者核心技能树分支基础能力&#xff1a;语法与工具 mastery精通至少一门主流语言&#xff08;如Python/JavaScript/Go&#xff09;熟…

作者头像 李华
网站建设 2026/5/16 17:17:22

OpenWrt嵌入式Linux开发入门:从编译到部署的完整实践指南

1. 项目概述&#xff1a;为什么选择OpenWrt作为嵌入式开发的起点 如果你对Linux系统有一定了解&#xff0c;并且想踏入嵌入式开发的大门&#xff0c;或者你是一个网络爱好者&#xff0c;想让家里的路由器“脱胎换骨”&#xff0c;那么OpenWrt绝对是一个绕不开的名字。它不是一…

作者头像 李华