Shell 脚本编程基础:从入门到实践

前言

在 Linux 和 Unix 系统中,Shell 脚本编程是自动化系统管理任务、批量处理文件以及快速执行命令的强大工具。本文讲详细讲解shell基础脚本的书写语法。(本文将以 Ubuntu 版本示例)

编程基础

脚本基本结构

// 一个shell脚本文件中主要包含以下内容
各种系统命令的组合
数据存储:变量、数组
表达式:a + b 
控制语句:if
// 格式要求:首行shebang机制
#!/bin/bash 
#!/usr/bin/python
#!/usr/bin/perl 
#!/usr/bin/ruby
#!/usr/bin/lua

Shell 脚本创建过程

1. 用编辑器创建新文件,首行必须是 shell 声明(shebang),编辑完成后保存退出
2. 添加可执行权限
3. 运行脚本
// 新建文件
[root@ubuntu ~]# vim test.sh
#!/bin/bash
echo "hello world"
// 添加执行权限
[root@ubuntu ~]# chmod +x test.sh
// 执行
// 注意,执行时需要添加路径,否则可能无法执行成功,因为系统会识别为执行命令,只会从$PATH路径下寻找
[root@ubuntu ~]# ./test.sh 
hello world

脚本注释规范

一般要注明作者,创建时间,修改时间,文件名,版本号,以及该程序的功能及作用。

[root@ubuntu2204 ~]# vim test.sh
#!/bin/bash
#
#****************************************************
#Author:           dayunzi
#QQ:               123456
#Date:             2022-08-16
#FileName:         test.sh
#URL:               http://www.dayunzi.com
#Description:       test
#Copyright(C):     2022 All right
#****************************************************
echo "hello world"

当前进程中执行

// test.sh
name="dayunzi"
age=27
// 当前进程中执行脚本会一直影响当前Shell会话
[root@ubuntu:~]$ . test.sh 
[root@ubuntu:~]$ echo $name; echo $age
dayunzi
27

子进程中执行

// test.sh
name="dayunzi"
age=27
// 在子进程中执行脚本意味着这是在一个独立的Shell实例中运行,不会影响当前会话
// 输出为空
[root@ubuntu:~]$ ./test.sh 
[root@ubuntu:~]$ echo $name; $age

执行前检查语法

// test.sh
name="dayunzi"
age=27"
// 只能检查语法错误,不能检查命令,也不会执行脚本
[root@ubuntu:~]$ bash -n test.sh
test.sh: line 13: unexpected EOF while looking for matching `"'

调试并执行脚本

// test.sh
name=dayunzi
age=27
car lscpu
// 逐行执行命令,并输出结果,可以检查命令错误
[root@ubuntu:~]$ bash -x test.sh 
+ name=dayunzi
+ age=27
+ car lscpu
test.sh: line 14: car: command not found

总结

错误类型检查命令
语法错误bash -n
命令错误bash -x
逻辑错误bash -x

错误案例

// test1.sh
#!/bin/bash
cat > test.conf<<EOF
$(hostname)
$(hostname -I)
EOF 
echo "==== over ===="
// 执行报错
// 编写脚本是要注意空格
[root@ubuntu:~]$ bash test1.sh
test1.sh: line 6: warning: here-document at line 2 delimited by end-of-file (wanted `EOF')
// 检查空格
[root@ubuntu:~]$ cat -nA test1.sh
     1	#!/bin/bash$
     2	cat > test.conf<<EOF$
     3	$(hostname)$
     4	$(hostname -I)$
     5	EOF $
     6	echo "==== over ===="$

变量

变量赋值

name='string'
name="$USER"
name=`COMMAND`
name=$(COMMAND)

变量追加

name+=string
name+="string"

变量引用

$name
${name}

保留格式

// 空格分隔
echo $variable
// 保留原格式
echo "$variable"

删除变量

unset <name>
// 删除变量后,引用不存在的变量输出为空
[root@ubuntu:~]$ name=dayunzi
[root@ubuntu:~]$ title=ceo
[root@ubuntu:~]$ echo $name $title
dayunzi ceo
[root@ubuntu:~]$ unset name title
[root@ubuntu:~]$ echo $name $tile

思考

编写一个脚本,显示当前主机系统信息

// 打开并编辑一个文件
// 将执行成功并获取正确主机系统信息的命令输入到文件中
[root@ubuntu:~]$  vim sysyinfo.sh
echo -ne "hostname:	"
hostname
echo -ne "ipv4:		"
ip add |head -n 3 |tail -1 |tr -s " " |cut -d " " -f3
echo -ne "os:		"
echo -ne "$(cat /etc/os-release |head -n 2 |tail -1 |cut -d '"' -f2) "
echo -e "$(cat /etc/os-release |head -n 4 |tail -1 |cut -d '"' -f2)"
echo -n "kernel:		"
uname -r
echo -n "cpu:		"
lscpu |head -n 9 |tail -1 |tr -s " " |cut -d: -f2
echo -n "Mem:		"
free -h | grep  "^Mem" |tr -s " "|cut -d " " -f2
echo -n "disk:		"
df -h |grep "^/dev/m" |tr -s " " |cut -d " " -f2
// 添加执行权限
[root@ubuntu:~]$  chmod +x sysinfo.sh
// 执行脚本
[root@ubuntu:~]$  ./sysinfo.sh

环境变量

// test6.sh
#!/bin/bash
echo $var1
echo $var2
echo $PATH
echo $ps1
// 定义变量
[root@ubuntu:~]$ var=123;export var2=456
// 执行脚本
// 普通定义的变量在子进程中执行时不会生效,而export将变量导出为环境变量
[root@ubuntu:~]$ bash test6.sh

456
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

只读变量

// 设置只读变量,不能修改和删除,但退出会话不再生效
// 永久生效可写入配置文件中,可防止恶意修改关键变量的值
[root@ubuntu:~]$ readonly PI=3014159
[root@ubuntu:~]$ echo $PI
3014159
[root@ubuntu:~]$ PI=314
-bash: PI: readonly variable
[root@ubuntu:~]$ unset PI
-bash: unset: PI: cannot unset: readonly variable

位置变量

项目Value
$1,$2…代表第1个参数、第2个参数…
$0运行脚本的命令名
$#参数的总和
$@代表所有位置参数,每个参数独立
$*代表所有位置参数,将所有参数看作一个整体
$?代表最后一个命令的退出状态码(0代表成功,1-255代表失败)
$$代表当前脚本的进程
$!代表最后一个后台命令的进程id
$_代表最后一个命令的最后一个参数
// 打开并编辑文件
[root@ubuntu:~]$ vim arg.sh 
# !/bin/bash
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "10st arg is ${10}"
echo "11st arg is ${11}"
echo "The number of arg is $#"
echo "All args are $*"
echo "All args are $@"
echo "The scriptname is `basename $0`"
// 执行脚本
[root@ubuntu:~]$ bash arg.sh {a..z}
1st arg is a
2st arg is b
3st arg is c
10st arg is j
11st arg is k
The number of arg is 26
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
The scriptname is arg.sh

思考

写一个使用删除命令时安全备份的脚本

// 打开并编辑文件
[root@ubuntu:~]$ vim rm.sh
# !/bin/bash
// 将告警输出结果标红
WARNING_COLOR="echo -e \E[1;31m"
END="\E[0m"
// 定义变量
DIR=/tmp/`date +%F_%H-%M-%S`
// 创建目录
mkdir $DIR
// 剪切到创建的目录下
mv  $*  $DIR
// 输出告警自定义文本
${WARNING_COLOR}Move $* to $DIR $END
// 添加执行权限
[root@ubuntu:~]$ chmod +x rm.sh
// 定义别名
[root@ubuntu:~]$ alias rm='/root/rm.sh'
// 创建一系列文件
[root@ubuntu:~]$ touch {1..10}.txt
// 删除批量文件,脚本自动将删除的文件进行备份
[root@ubuntu:~]$ rm *.txt
Move 10.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt to /tmp/2020-04-01_15-15-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值