Shell 脚本编程保姆级教程(上)

简介: Shell 脚本编程保姆级教程(上)

一、运行第一个 Shell 脚本

1.1 Shell 脚本

Shell 脚本(shell script),是一种为 shell 编写的脚本程序。

业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。


由于习惯的原因,简洁起见,本文出现的 "shell编程" 都是指 shell 脚本编程,不是指开发 shell 自身。

1.2 Shell 环境

Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。

Linux 的 Shell 种类众多,常见的有:

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)
  • ……

本教程关注的是 Bash,也就是 Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。


在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。


#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。

1.3 运行脚本

打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh,扩展名为 sh(sh代表shell)

1. #!/bin/bash
2. echo "Hello World !"
chmod +x ./test.sh  #使脚本具有执行权限
./test.sh  #执行脚本

另一种则是,直接运行解释器

/bin/sh test.sh

二、Shell 变量

2.1 变量名规则

注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:

  • 只包含字母、数字和下划线: 变量名可以包含字母(大小写敏感)、数字和下划线 _,不能包含其他特殊字符。
  • 不能以数字开头: 变量名不能以数字开头,但可以包含数字。
  • 避免使用 Shell 关键字: 不要使用Shell的关键字(例如 if、then、else、fi、for、while 等)作为变量名,以免引起混淆。
  • 使用大写字母表示常量: 习惯上,常量的变量名通常使用大写字母,例如 PI=3.14。
  • 避免使用特殊符号: 尽量避免在变量名中使用特殊符号,因为它们可能与 Shell 的语法产生冲突。
  • 避免使用空格: 变量名中不应该包含空格,因为空格通常用于分隔命令和参数。

有效的 Shell 变量名示例如下:

man="handsome"
LD_LIBRARY_PATH="/bin/"
_var="123"
var2="abc"

除了显式地直接赋值,还可以用语句给变量赋值,如:

for file in `ls /etc`
for file in $(ls /etc)

2.2 使用变量

使用一个定义过的变量,只要在变量名前面加美元符号即可,如:

#!/bin/bash
name="zhangsan"
echo $name
echo ${name}

推荐给所有变量加上花括号,这是个好的编程习惯

已定义的变量,可以被重新定义

#!/bin/bash
your_name="tom"
echo $your_name
 
your_name="alibaba"
echo $your_name

2.3 只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变

#!/bin/bash
your_name="tom"
echo $your_name
 
readonly your_name
your_name="alibaba"
echo $your_name

结果报错

2.4 删除变量

使用 unset 命令可以删除变量

#!/bin/bash
your_name="tom"
echo $your_name
 
unset your_name
echo $your_name

删除了,值为空

2.5 变量类型

declare 命令

declare 命令用于声明和定义变量的属性,如只读、数组、整数等。

常用选项

  • -a:声明数组变量。
  • -A:声明关联数组变量。
  • -i:声明整数变量。
  • -r:声明只读变量。
  • -x:声明环境变量(类似于 export)。
  • -l:将变量值转换为小写字母。
  • -u:将变量值转换为大写字母。

typeset 命令

typeset 命令在功能上与 declare 相似,用于声明和定义变量的属性。在 Bash 中,typesetdeclare 的同义词,但在一些其他 Shell 中(如 ksh),typeset 更常用。

declare 的选项基本相同,typeset 也支持以下选项:

  • -a:声明数组变量。
  • -A:声明关联数组变量。
  • -i:声明整数变量。
  • -r:声明只读变量。
  • -x:声明环境变量(类似于 export)。
  • -l:将变量值转换为小写字母。
  • -u:将变量值转换为大写字母。
#!/bin/bash
typeset -i num
num=66
 
age=19
typeset -r age
 
typeset -l name
name="MORANT"
 
typeset -u sex
sex="man"
 
typeset -a array
array=(1 2 3)
 
typeset -x export_var="Hello!"
 
typeset -A assoc
assoc[city]="Enshi"
assoc[fell]="good"
 
echo ${num}
echo ${name}
echo ${sex}
echo ${array[1]}
echo ${export_var}
echo ${assoc[city]}

2.6 Shell 字符串

单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字符串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。

双引号的优点:

  • 双引号里可以有变量
  • 双引号里可以出现转义字符

拼接字符串

#!/bin/bash
name="joker"
say="I am $name"
echo ${say}

获取字符串长度

#!/bin/bash
name="joker"
say="I am $name"
echo ${#say}

提取子字符串

#!/bin/bash
name="joker"
say="I am $name"
echo ${say:0:4}

查找子字符串

#!/bin/bash
name="joker"
say="I am $name"
echo `expr index "$say" j`
  • 反引号(`)的使用:反引号用于命令替换,将其内部的命令输出作为外部命令的参数。换句话说,expr index "$say" j 的输出将作为 echo 的参数。
  • expr 命令expr 是一个用于计算表达式的命令,支持算术运算、字符串操作等。这里使用的是 index 操作。
  • index 操作expr index 返回字符串中第一次出现给定字符的位置(从1开始计数)。


2.7 Shell 数组

读取数组

#!/bin/bash
typeset -a array_num
array_num=(1 2 3 4 5)
echo ${array_num[0]}
echo ${array_num[1]}
echo ${array_num[2]}
echo ${array_num[3]}
echo ${array_num[4]}
echo ${array_num[@]}

使用 @ 符号可以获取数组中的所有元素

获取数组的长度

#!/bin/bash
typeset -a array_num
array_num=(1 2 3 4 5)
length=${#array_num[@]}
echo $length
length=${#array_num[*]}
echo $length
length=${#array_num[0]}
echo $length

获取数组长度的方法与获取字符串长度的方法相同

2.8 注释

#--------------------------------------------
# 这是一个注释
 
 
:<<EOF
注释内容...
注释内容...
注释内容...
EOF
 
 
: <<'COMMENT'
这是注释的部分。
可以有多行内容。
COMMENT
 
:<<'
注释内容...
注释内容...
注释内容...
'
 
:<<!
注释内容...
注释内容...
注释内容...
!
 
 
: '
这是注释的部分。
可以有多行内容。
'

三、Shell 传递参数

#!/bin/bash
echo "请传递三个参数"
echo "执行文件名:$0"
echo "第一个参数为:$1"
echo "第一个参数为:$2"
echo "第一个参数为:$3"

$0 为执行的文件名(包含文件路径)

参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。
如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
#!/bin/bash
echo "请传递三个参数"
echo "执行文件名:$0"
echo "第一个参数为:$1"
echo "第一个参数为:$2"
echo "第一个参数为:$3"
echo "将所有参数作为一个字符串显示:$*"
echo "脚本当前运行的 ID:$$"
echo "后台运行的最后一个进程的 ID:$!"
echo "引号分割所有参数:$@"
echo "显示 Shell 使用的当前选项:$-"
echo "显示最后命令的退出状态,0 表示没有错误:$?"

四、Shell 基本运算符

4.1 算术运算符

运算符 说明 举例
+ 加法 `expr $a + $b` 结果为 30。
- 减法 `expr $a - $b` 结果为 -10。
* 乘法 `expr $a \* $b` 结果为  200。
/ 除法 `expr $b / $a` 结果为 2。
% 取余 `expr $b % $a` 结果为 0。
= 赋值 a=$b 把变量 b 的值赋给 a。
== 相等。用于比较两个数字,相同则返回 true。 [ $a == $b ] 返回 false。
!= 不相等。用于比较两个数字,不相同则返回 true。 [ $a != $b ] 返回 true。
#!/bin/bash
a=10
b=20
 
val=`expr $a + $b`
echo "a + b : $val"
 
val=`expr $a - $b`
echo "a - b : $val"
 
val=`expr $a \* $b`
echo "a * b : $val"
 
val=`expr $b / $a`
echo "b / a : $val"
 
val=`expr $b % $a`
echo "b % a : $val"
 
if [ $a == $b ]
then
   echo "a 等于 b"
fi
if [ $a != $b ]
then
   echo "a 不等于 b"
fi

4.2 关系运算符

运算符 说明 举例
-eq 检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 false。
-ne 检测两个数是否不相等,不相等返回 true。 [ $a -ne $b ] 返回 true。
-gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false。
-lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。
-ge 检测左边的数是否大于等于右边的,如果是,则返回 true。 [ $a -ge $b ] 返回 false。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ $a -le $b ] 返回 true。
#!/bin/bash
a=10
b=20
 
if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
   echo "$a -ne $b: a 不等于 b"
else
   echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
   echo "$a -gt $b: a 大于 b"
else
   echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
   echo "$a -lt $b: a 小于 b"
else
   echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
   echo "$a -ge $b: a 大于或等于 b"
else
   echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
   echo "$a -le $b: a 小于或等于 b"
else
   echo "$a -le $b: a 大于 b"
fi

4.3 布尔运算符

运算符 说明 举例
! 非运算,表达式为 true 则返回 false,否则返回 true。 [ ! false ] 返回 true。
-o 或运算,有一个表达式为 true 则返回 true。 [ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a 与运算,两个表达式都为 true 才返回 true。 [ $a -lt 20 -a $b -gt 100 ] 返回 false。
#!/bin/bash
a=10
b=20
 
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a == $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
   echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
   echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
   echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
   echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
   echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
   echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi

4.4 逻辑运算符

运算符 说明 举例
&& 逻辑的 AND [[ $a -lt 100 && $b -gt 100 ]] 返回 false
|| 逻辑的 OR [[ $a -lt 100 || $b -gt 100 ]] 返回 true
#!/bin/bash
a=10
b=20
 
if [[ $a -lt 100 && $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi
 
if [[ $a -lt 100 || $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi

4.5 字符串运算符

运算符 说明 举例
= 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
!= 检测两个字符串是否不相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n 检测字符串长度是否不为 0,不为 0 返回 true。 [ -n "$a" ] 返回 true。
$ 检测字符串是否不为空,不为空返回 true。 [ $a ] 返回 true。
#!/bin/bash
a="abc"
b="efg"
 
if [ $a = $b ]
then
   echo "$a = $b : a 等于 b"
else
   echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
   echo "-z $a : 字符串长度为 0"
else
   echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]
then
   echo "-n $a : 字符串长度不为 0"
else
   echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
   echo "$a : 字符串不为空"
else
   echo "$a : 字符串为空"
fi

4.6 文件测试运算符

操作符 说明 举例
-b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -c $file ] 返回 false。
-d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。
-p file 检测文件是否是有名管道,如果是,则返回 true。 [ -p $file ] 返回 false。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。 [ -u $file ] 返回 false。
-r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
-w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。
#!/bin/bash
file="/var/www/html/index.html"
if [ -r $file ]
then
   echo "文件可读"
else
   echo "文件不可读"
fi
if [ -w $file ]
then
   echo "文件可写"
else
   echo "文件不可写"
fi
if [ -x $file ]
then
   echo "文件可执行"
else
   echo "文件不可执行"
fi
if [ -f $file ]
then
   echo "文件为普通文件"
else
   echo "文件为特殊文件"
fi
if [ -d $file ]
then
   echo "文件是个目录"
else
   echo "文件不是个目录"
fi
if [ -s $file ]
then
   echo "文件不为空"
else
   echo "文件为空"
fi
if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi

五、Shell echo 命令

显示普通字符串

显示转义字符

显示变量

#!/bin/sh
read name 
echo "$name It is a test"

read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量

显示换行

显示不换行

将 \n 改为 \c 即可

显示结果定向至文件

显示命令执行结果

六、Shell printf 命令

printf 命令的语法:

printf  format-string  [arguments...]

参数说明:

  • format-string: 一个格式字符串,它包含普通文本和格式说明符。
  • arguments: 用于填充格式说明符的参数列表。。

格式说明符由 % 字符开始,后跟一个或多个字符,用于指定输出的格式。常用的格式说明符包括:

  • %s:字符串
  • %d:十进制整数
  • %f:浮点数
  • %c:字符
  • %x:十六进制数
  • %o:八进制数
  • %b:二进制数
  • %e:科学计数法表示的浮点数
#!/bin/bash
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg  
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543 
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876

%-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐)

 

相关文章
|
1月前
|
Shell
一个用于添加/删除定时任务的shell脚本
一个用于添加/删除定时任务的shell脚本
75 1
|
17天前
|
Shell Linux 测试技术
6种方法打造出色的Shell脚本
6种方法打造出色的Shell脚本
39 2
6种方法打造出色的Shell脚本
|
3天前
|
XML JSON 监控
Shell脚本要点和难点以及具体应用和优缺点介绍
Shell脚本在系统管理和自动化任务中扮演着重要角色。尽管存在调试困难、可读性差等问题,但其简洁高效、易于学习和强大的功能使其在许多场景中不可或缺。通过掌握Shell脚本的基本语法、常用命令和函数,并了解其优缺点,开发者可以编写出高效的脚本来完成各种任务,提高工作效率。希望本文能为您在Shell脚本编写和应用中提供有价值的参考和指导。
12 1
|
8天前
|
Ubuntu Shell 开发工具
ubuntu/debian shell 脚本自动配置 gitea git 仓库
这是一个自动配置 Gitea Git 仓库的 Shell 脚本,支持 Ubuntu 20+ 和 Debian 12+ 系统。脚本会创建必要的目录、下载并安装 Gitea,创建 Gitea 用户和服务,确保 Gitea 在系统启动时自动运行。用户可以选择从官方或小绿叶技术博客下载安装包。
22 2
|
22天前
|
监控 网络协议 Shell
ip和ip网段攻击拦截系统-绿叶结界防火墙系统shell脚本
这是一个名为“小绿叶技术博客扫段攻击拦截系统”的Bash脚本,用于监控和拦截TCP攻击。通过抓取网络数据包监控可疑IP,并利用iptables和firewalld防火墙规则对这些IP进行拦截。同时,该系统能够查询数据库中的白名单,确保合法IP不受影响。此外,它还具备日志记录功能,以便于后续分析和审计。
43 6
|
18天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
1月前
|
Shell
Shell编程(下)
Shell编程(下)
88 1
|
1月前
|
Shell Linux Windows
Shell编程(上)
Shell编程(上)
40 1
|
1月前
|
JavaScript 前端开发 Shell
Shell 教程
10月更文挑战第1天
29 4
|
1月前
|
存储 运维 监控
自动化运维:使用Shell脚本简化日常任务
【9月更文挑战第35天】在IT运维的日常工作中,重复性的任务往往消耗大量的时间。本文将介绍如何通过编写简单的Shell脚本来自动化这些日常任务,从而提升效率。我们将一起探索Shell脚本的基础语法,并通过实际案例展示如何应用这些知识来创建有用的自动化工具。无论你是新手还是有一定经验的运维人员,这篇文章都会为你提供新的视角和技巧,让你的工作更加轻松。
49 2