【Shell 脚本入门】轻松上手的实战指南

🌈 个人主页:Zfox_

🔥 系列专栏:Shell脚本编程

目录

  • [一:🔥 什么是 Shell](#一:🔥 什么是 Shell)
    • [🦋 常见的 Shell 类型](#🦋 常见的 Shell 类型)
  • [二:🔥 什么是 Shell 脚本](#二:🔥 什么是 Shell 脚本)
    • [🦋 Shell 脚本规则](#🦋 Shell 脚本规则)
    • [🦋 第一个 Shell 脚本](#🦋 第一个 Shell 脚本)
    • [🦋 Shebang](#🦋 Shebang)
    • [🦋 脚本的常用执行方式](#🦋 脚本的常用执行方式)
    • [🦋 第二个 Shell 脚本:多命令处理](#🦋 第二个 Shell 脚本:多命令处理)
    • [🦋 Shell 的优势](#🦋 Shell 的优势)
  • [三:🔥 Shell 中的变量](#三:🔥 Shell 中的变量)
    • [🦋 系统变量](#🦋 系统变量)
    • [🦋 自定义变量](#🦋 自定义变量)
    • [🦋 单引号 双引号区别](#🦋 单引号 双引号区别)
    • [🦋 特殊变量](#🦋 特殊变量)
    • [🦋 特殊变量实践](#🦋 特殊变量实践)
    • [🦋 Shell 变量面试题](#🦋 Shell 变量面试题)
    • [🦋 环境变量设置](#🦋 环境变量设置)
    • [🦋 检查系统环境变量的命令](#🦋 检查系统环境变量的命令)
    • [🦋 撤销环境变量](#🦋 撤销环境变量)
    • [🦋 设置只读变量](#🦋 设置只读变量)
    • [🦋 环境变量初始化与加载顺序](#🦋 环境变量初始化与加载顺序)
  • [四:🔥 Shell 子串](#四:🔥 Shell 子串)
    • [🦋 bsah 一些基础的内置命令](#🦋 bsah 一些基础的内置命令)
    • [🦋 Shell 子串的花式用法](#🦋 Shell 子串的花式用法)
    • [🦋 字符串截取](#🦋 字符串截取)
    • [🦋 应用:批量修改文件名](#🦋 应用:批量修改文件名)
    • [🦋 特殊 Shell 扩展变量](#🦋 特殊 Shell 扩展变量)
  • [五:🔥 共勉](#五:🔥 共勉)

一:🔥 什么是 Shell

🦞 Shell 是一块包裹着系统核心的壳,处于操作系统的最外层,与用户直接对话,把用户的输入, 解释给操作系统,然后处理操作系统的输出结果,输出到屏幕给与用户看到结果。

Shell 是用户与系统交互的主要方式之一。

Shell 的作用是

  • 解释执行用户输入的命令或程序等
  • 用户输入一条命令,Shell 就解释一条键盘输入命令,Linux 给与响应的方式,称之为交互式

我们想要获取计算机的数据,不可能每次都编写程序,编译后,再运行,再得到我们想要的,例如你想找到一个文件,可以先写一段 C语言的代码,然后调用系统函数,通过 gcc 编译后,运行程序才能找到文件。

因此有大牛开发出了 Shell 解释器,能够让我们方便的使用 Linux,例如只要敲下 ls - lh 这样的字符串,Shell 解释器就会针对这句话翻译,解释成 ls-l -h 然后执行 ,通过终端输出结果,无论是图形化或是命令行界面。

即使我们用的图形化,点点点的动作,区别也只是

  • 命令行操作,Shell 解释执行后,输出结果到黑屏命令行界面
  • 图形化操作,Shell 接受点击动作,输出图案数据

🦋 常见的 Shell 类型

  • Bash (Bourne Again Shell)
    最广泛使用的 Shell,是 GNU 项目的一部分,提供了丰富的功能和强大的脚本支持。
    默认的 Shell 为大多数 Linux 发行版和 macOS(直到 macOS Mojave)。
  • Sh (Bourne Shell)
    最早的 Unix Shell,是 Bash 的前身,功能相对简单。
  • Tcsh (C Shell)
    提供了类似于 C 语言的语法,适合熟悉 C 语言的用户。
  • Zsh (Z Shell)
    提供了许多高级功能,如自动补全、主题支持等,是 macOS Catalina 及以后版本的默认 Shell。
  • Fish (Friendly Interactive Shell)
    一个现代的 Shell,强调用户友好性和交互性,提供了智能的自动补全和语法高亮等功能。

二:🔥 什么是 Shell 脚本

🍫 当命令或者程序语句写在文件中,我们执行文件,读取其中的代码,这个程序文件就称之为 Shell 脚本

Shell 脚本里定义多条 Linux 命令以及循环控制语句,然后将这些 Linux 命令一次性执行完毕,执行脚本文件的方式称之为,非交互式方式,

  • windows 中存在 *.bat 批处理脚本
  • Linux 中常用 *.sh 脚本文件

Shell 脚本语言属于一种弱类型语言,无需声明变量类型,直接定义使用强类型语言,必须先定义变量类型,确定是数字、字符串等,之后再赋予同类型的值 centos7 系统中支持的 Shell 情况,有如下种类

csharp 复制代码
# cat /etc/shells 
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash
/usr/bin/tmux
/usr/bin/screen

Linux 默认 Shell

csharp 复制代码
# echo $SHELL
/bin/bash

🦋 Shell 脚本规则

在 Linux 系统中,Shell 脚本或者称之为 (bash shell程序) 通常都是 vim 编辑,由 Linux 命令、bash shell 指令、逻辑控制语句和注释信息组成。

🦋 第一个 Shell 脚本

csharp 复制代码
# vim test1.sh 
# cat test1.sh 

# 第一个 shell 脚本 这是注释
#!/bin/bash

echo "hello world!"

运行 Shell 脚本

csharp 复制代码
# bash test1.sh 
hello world!

🦋 Shebang

🐳 计算机程序中 Shebang 指的是出现在文本文件的第一行前两个字符 #!

  • 就是指明这个代码文件用哪个解释器去读

在 Unix 系统中,程序会分析 Shebang 后面的内容,作为解释器的指令,例如

  • #!/bin/bash 开头的文件,程序在执行的时候会调用 /bin/bash ,也就是 bash 解释器
  • 以 #!/usr/bin/python 开头的文件,代表指定python解释器去执行
  • 以 #!/usr/bin/env 解释器名称 ,是一种在不同平台上都能正确找到解释器的办法

注意事项:

  • 如果脚本未指定 Shebang ,脚本执行的时候,默认用当前 shell 去解释脚本,即 $SHELL。
  • 如果 Shebang 指定了可执行的解释器,如 /bin/bash /usr/bin/python ,脚本在执行时,文件名会作为参数传递给解释器
  • 如果 #! 指定的解释程序没有可执行权限,则会报错"bad interpreter: Permission denied"。
  • 如果 #! 指定的解释程序不是一个可执行文件,那么指定的解释程序会被忽略,转而交给当前的 SHELL 去执行这个脚本。
  • 如果 #! 指定的解释程序不存在,那么会报错 "bad interpreter: No such file or directory"。
  • #! 之后的解释程序,需要写其绝对路径 (如:#!/bin/bash),它是不会自动到 $PATH 中寻找解释器的。。
  • 如果你使用 "bash test.sh" 这样的命令来执行脚本,那么 #! 这一行将会被忽略掉,解释器当然是用命令行中显式指定的 bash。

🦋 脚本的常用执行方式

🦈 第一种:采用 bashsh + 脚本的相对路径或绝对路径(不用赋予脚本 +x 权限)

sh + 脚本的相对路径

csharp 复制代码
$ sh helloworld.sh 
Helloworld

sh + 脚本的绝对路径

csharp 复制代码
$ sh /home/zfox/datas/helloworld.sh 
helloworld

bash+脚本的相对路径

csharp 复制代码
$ bash helloworld.sh 
Helloworld

bash + 脚本的绝对路径

csharp 复制代码
$ bash /home/zfox/datas/helloworld.sh 
Helloworld

第二种:采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限 + x)

(a)首先要赋予 helloworld.sh 脚本的 + x权限

csharp 复制代码
$ chmod 777 helloworld.sh

(b)执行脚本

相对路径(推荐使用)

csharp 复制代码
$ ./helloworld.sh 
Helloworld

绝对路径

csharp 复制代码
$ /home/zfox/datas/helloworld.sh 
Helloworld

注意:第一种执行方法,本质是 bash解析器 帮你执行脚本,所以脚本本身不需要执行权限。第二种执行方法,本质是脚本需要自己执行,所以需要执行权限

🦋 第二个 Shell 脚本:多命令处理

(1)需求: 在 /home/zfox/ 目录下创建一个 ljw.txt, 在 ljw.txt 文件中增加 I love ljw

(2)案例实操:

csharp 复制代码
$ touch batch.sh
$ vim batch.sh

batch.sh 中输入如下内容

csharp 复制代码
#!/bin/bash

cd /home/zfox
touch ljw.txt
echo "I love ljw" >> ljw.txt

🦋 Shell 的优势

虽然有诸多脚本编程语言,但是对于 Linux 操作系统内部应用而言,Shell 是最好的工具,Linux 底层命令都支持 Shell 语句,以及结合三剑客 (grep、sed、awk) 进行高级用法。

  • 擅长系统管理脚本开发,如软件启停脚本、监控报警脚本、日志分析脚本

每个语言都有自己擅长的地方,扬长避短,达到高效运维的目的是最合适的

三:🔥 Shell 中的变量

  • 变量定义与赋值,注意变量与值之间不得有空格
csharp 复制代码
name="zfox"

变量名
变量类型,bash默认把所有变量都认为是字符串

bash变量是弱类型,无需事先声明类型,是将声明和赋值同时进行
  • 变量替换写弓|用
csharp 复制代码
# name="zfox带你学bash"

# echo ${name}
zfox带你学bash

# echo $name	# 可以省略花括号
zfox带你学bash
  • 变量名规则

    • 名称定义要做到见名知意,切按照规则来,切不得引用保留关键字(help检查保留字)
    • 只能包含数字、字母、下划线
    • 不能以数字开头
    • 不能用标点符号
    • 变量名严格区分大小写
  • 变量的作用域

    • 本地变量。只针对当前的 shell 进程

🦋 系统变量

1)常用系统变量

HOME、PWD、SHELL、USER等

2)案例实操

(1)查看系统变量的值

csharp 复制代码
$ echo $HOME
/home/zfox

(2)显示当前 Shell 中所有变量:set

csharp 复制代码
$ set
BASH=/bin/bash
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()

🦋 自定义变量

1.基本语法

(1)定义变量:变量=值

(2)撤销变量:unset 变量

(3)声明静态变量:readonly 变量,注意:不能unset

🦋 单引号 双引号区别

单引号变量,不识别特殊语法
双引号变量,能识别特殊符号
反引号,引用命令执行结果,等于 $() 用法

🌰 举例子:

csharp 复制代码
# name="奥里给"
# echo ${name}
奥里给

# 单引号
# name2='${name}'
# echo $name2
${name}

# 双引号
# name2="${name}"
# echo $name2
奥里给

🦋 特殊变量

  • $?
    • 0 成功
    • 1-255 错误码

Shell 的特殊变量,用在如脚本,函数传递参数使用,有如下特殊的,位置参数变量

csharp 复制代码
$0		获取shel1脚本文件名,以及脚本路径
$n		获取shel1脚本的第n个参数,n在1~9之间,如$1,$2,$9,大于9则需要写,${10},参数空格隔开
$#		获取执行的she11脚本后面的参数总个数
$*		获取she11脚本所有参数,不加引号等同于 $@ 作用,加上引号 "$*" 作用是 接收所有参数为单个字符串,"$1 $2.
$@		不加引号,效果同上,加引号,是接收所有参数为独立字符串,如"$1" "$2" "$3"...,空格保留

🦋 特殊变量实践

csharp 复制代码
#! bin/bash
# 注意单引号和双引号的区别
echo '特殊变量 $0 $1 $2 ... 的实践'
echo '结果: ' $0 $1 $2

echo '############################'
echo '特殊变量$# 获取参数个数的总数'
echo '结果: ' $#


echo '############################'
echo '特殊变量$* 实践'
echo '结果: ' $*

echo '############################'
echo '特殊变量 $@ 实践'
echo '结果: ' $@
csharp 复制代码
#! /bin/bash

# $* 和 $@ 的区别
echo 'print each param from $*'
for var in "$*"
do 
	echo "$var"
done
echo 'print each param from $@'
for var in "$@"
do
	echo "$var"
done
csharp 复制代码
$*和$@的区别你了解吗?

$*和 $@ 都表示传递给函数或脚本的所有参数

当 $*和 $@ 不被双引号""包围时,它们之间没有任何区别,都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔。
但是当它们被双引号""包含时,就会有区别了:

"$*"会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。'yu chao 180 180 180 180"

"$@"仍然将每个参数都看作一份数据,彼此之间是独立的。
"chao'
"180"
"180"
"180"

比如传递了 5个参数,那么对于"$*"来说,这 5 个参数会合并到一起形成一份数据,它们之间是无法分割的;而对于"$@"来说,这5 个参数是相互独立的,它们是 5 份数据。

如果使用 echo 直接输出"$*"和"$@"做对比,是看不出区别的;但如果使用 for 循环来逐个输出数据,立即就能看出区别来。

🦋 Shell 变量面试题

问,如下输入什么内容

csharp 复制代码
# cat test.sh
user1=`whoami`

# sh test.sh
# echo $user1

A.当前用户
B.zfox
c.空



答案选c

`linux命令`
在 linux 中反引号,中的命令执行结果会被保留下来

csharp 复制代码
# name=`ls`
# echo $name
test1.sh test2.sh test3.sh

解答:

  1. 每次调用 bash/sh 解释器执行脚本,都会开启一个子 shell,因此不保留当前的 shell 变量,通过 pstree 命令检查进程树
  2. 调用 source 或者 点符号,在当前 shell 环境加载脚本,因此保留变量

🦋 环境变量设置

环境变量一般指的是用 export 内置命令导出的变量,用于定义 shell 的运行环境、保证 shell 命令的正确执行。

shell 通过环境变量确定登录的用户名、PATH路径、文件系统等各种应用。

环境变量可以在命令行中临时创建,但是用户退出shell终端,变量即丢失,如要永久生效,需要修改环境变量配置文件

  • 用户个人配置文件 ~/.bash profile、 ~/.bashrc 远程登录用户特有文件
  • 全局配置文件 /etc/profile/etc/bashrc,且系统建议最好创建在 /etc/profile.d/,而非直接修改主文件,修改全局配置文件,影响所有登录系统的用户

🦋 检查系统环境变量的命令

  • set,输出所有变量,包括全局变量、局部变量
  • env,当前用户的所有环境变量,包括全局环境变量和局部环境变量
  • declare,输出所有的变量,如同 set
  • export,显示和设置环境变量值

🦋 撤销环境变量

  • unset 变量名,删除变量或函数

🦋 设置只读变量

  • readonly,只有shell结束,只读变量失效
csharp 复制代码
直接readonly 显示当前系统只读变量

# readonly name="超哥"
# name="chaochao"
-bash:name:只读变量

🦋 环境变量初始化与加载顺序

四:🔥 Shell 子串

🦋 bsah 一些基础的内置命令

csharp 复制代码
echo
eval
exec
export
read
shift

echo 命令

csharp 复制代码
-n 不换行输出
-e 解析字符串中的特殊符号

\n 换行
\r 回车
\t 制表符 四个空格
\b 退格


# echo 你真胖;echo 你还挺可爱你真胖
你还挺可爱

# 不换行打印
# echo -n 你真胖;echo 你还挺可爱
你真胖你还挺可爱
# echo -n 你真胖;echo -n 你还挺可爱你真胖你还挺可爱 #

# echo -e "我看你挺\n好的"
我看你挺
好的

# printf
printf "你好\t我是\t吴彦祖"
你好		我是		吴彦祖

eval

执行多个命令

shell 复制代码
# eval ls;cd /tmp
del_data.sh 	hello.py 	special_var.sh 	t1.sh 
different.sh 	hello.sh 	nohup.out str1 	test.txt

exec

不创建子进程,执行后续命令, 且执行完毕后,自动 exit

csharp 复制代码
#  exec date
Fri 25 Apr 2025 08:56:41 AM CST

Connection closed.

Disconnected from remote host(Ubuntu-tencnt) at 08:56:41.

🦋 Shell 子串的花式用法

csharp 复制代码
${变量}							返回变量值
${#变量}							返回变量长度,字符长度
${变量:start}					返回变量 offset 数值之后的字符
${变量:start:length}				提取 offset 之后的 length 限制的字符
${变量#word}						从变量开头删除最短匹配的 word 子串
${变量##word}					从变量开头,删除最长匹配的 word
${变量%word}					    从变量结尾删除最短的 word
${变量%%word}					从变量结尾开始删除最长匹配的 word
${变量/pattern/string}			用 string 代替第一个匹配的 pattern
${变量//pattern/string)			用 string 代替所有的 pattern
csharp 复制代码
# name="yuchao180'

# echo $name
yuchao180
# echo ${name}
yuchao188

# echo ${#name}
9

# 截取子串的用法
# echo ${name:3}
hao180

# echo ${name:5}
o180
#设置起点,以及元素长度
# echo ${name:2:4}
chao
  • 多种统计长度的命令
csharp 复制代码
# echo $name
yuchao180

# echo $name | wc -l
1
# echo $name |wc -L
9

# 解释wc命令参数用法 -l 行数   -L 最长一行的长度
# cat test1.txt | wc -l
3
# cat test1.txt | wc -L
8 
  • 统计命令执行速度

字符串长度统计方式这么多,谁最快?
time 命令,统计命令执行时长
for 循环的 shell 编程知识语法

csharp 复制代码
for number in {1..100}
do
	echo $number
done
写在一行的方法
for num in {1..100}; do echo $num; done
csharp 复制代码
# 1.方法
# for n in {1..3}; do str1=`seg -s ":" 10`; echo $str1; done
1:2:3:4:5:6:7:8:9:10
1:2:3:4:5:6:7:8:9:10
1:2:3:4:5:6:7:8:9:10

# 结合 time 命令 ${#变量} 计算时间是13s
# time for n in {1..10000}; do char=`seq -s "chaoge" 100`; echo ${#char} &>/dev/null; done
real  0m13.956s		实际运行的时间
user  0m6.005s		用户态执行的时间
sys   0m5.868s		内核态执行的时间

# 使用 wc -L 命令计算时间
# time for n in {1..10000}; do char=`seq -s "chaoge" 100`; echo ${char} | wc-L &>/dev/null; done
real  0m49.262s		
user  0m18.843s		
sys   0m24.905s		

# expr命令的 length 函数统计
# time for n in {1..10000}; do char=`seq -s "chaoge" 100`; expr length "${char}" &>/dev/null; done
real  0m28.511s		
user  0m11.960s		
sys   0m12.046s		

Shell 编程,尽量使用 linux 内置的命令,内置的操作,和内置的函数,C语言开发,效率最高,尽可能的减少管道符的操作

🦋 字符串截取

删除匹配到的子串

cpp 复制代码
# name="I am chaoge"
# echo $name
I am chaoge

# echo ${name:2:2}
am

# echo ${name:3:5}
m cha

# name2="abcABC123ABcabc"

# #从开头匹配字符删除
# echo ${name2#a*c}
ABC123ABCabc

# echo ${name2##a*c}


# 利用%形式,从后向前匹配截取
# name2=abcABC123ABcabc

# echo ${name2%a*c}
abCABC123ABC

# echo ${name2%%a*c}

# echo ${name2%%a*C}
abcABC123ABCabc

# echo ${name2%a*C}
abcABC123ABCabc

替换字符串

csharp 复制代码
# str1="Hello,man,i am your brother."
# echo $str1
Hello,man,i am your brother.


# echo ${str1/man/boy}
Hello,boy,i am your brother.


#多次匹配替换
# echo $str1
Hello,man,i am your brother.

# echo ${str1/o/0}
HellO,man,i am your brother.

# echo ${str1//o/O}
HellO,man,i am yOur brOther.

🦋 应用:批量修改文件名

创建一批文件

cpp 复制代码
# touch chaochao_{1..5}_finished.jpg
# touch chaochao_{1..5}_finished.png

去掉剩下的所有 jpg 文件的 _finished 字符

编写 Shell 脚本如下:

csharp 复制代码
#! /bin/bash

for file_name in `ls *fin*jpg`; do mv $file_name `echo ${file_name//_finished/}` ; done

🦋 特殊 Shell 扩展变量

cpp 复制代码
如果parameter变量值为空,返回word字符串,赋值给result变量
result=${parameter:-word}

如果para变量为空,则word替代变量值,且返回其值
result=${parameter:=word}

如果para变量为空,word当作stderr输出,否则输出变量值
用于设置变量为空导致错误时,返回的错误信息
result=$fparameter:?word?

如果para变量为空,什么都不做,否则word返回
result=${parameter:+word}

五:🔥 共勉

😋 以上就是我对 【Shell 脚本开发】入门全套教程 的理解, 觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~ 😉

相关推荐
树℡独8 小时前
ns-3仿真之应用层(五)
服务器·网络·tcp/ip·ns3
嵩山小老虎8 小时前
Windows 10/11 安装 WSL2 并配置 VSCode 开发环境(C 语言 / Linux API 适用)
linux·windows·vscode
Fleshy数模9 小时前
CentOS7 安装配置 MySQL5.7 完整教程(本地虚拟机学习版)
linux·mysql·centos
a41324479 小时前
ubuntu 25 安装vllm
linux·服务器·ubuntu·vllm
Configure-Handler9 小时前
buildroot System configuration
java·服务器·数据库
津津有味道9 小时前
易语言TCP服务端接收刷卡数据并向客户端读卡器发送指令
服务器·网络协议·tcp·易语言
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.10 小时前
Keepalived VIP迁移邮件告警配置指南
运维·服务器·笔记
Genie cloud10 小时前
1Panel SSL证书申请完整教程
服务器·网络协议·云计算·ssl
一只自律的鸡10 小时前
【Linux驱动】bug处理 ens33找不到IP
linux·运维·bug
17(无规则自律)11 小时前
【CSAPP 读书笔记】第二章:信息的表示和处理
linux·嵌入式硬件·考研·高考