Skip to content

shell脚本入门

简介

Shell是命令解释器,用于解释用户对操作系统的操作 CentOS7默认使用的Shell是bash

编写Shell脚本

入门示例

1.编写demo.sh文件,示例:
----------
#!/bin/bash
cd /var/
ls
pwd
----------
- 各命令之间可以以;或者换行间隔
- 第一行声明 #!/bin/bash,在./demo.sh执行时会告诉系统使用bash解释执行
- 除了第一行外以#开头的一行都为注释, 建议注释单开一行

2. 授予执行的权限
chmod u-x demo.sh

3. 执行
在子进程中执行
bash demo.sh
./demo.sh

在当前进程执行
source ./demo.sh
. demo.sh

内建命令不需要创建子进程
内建命令对当前Shell生效

管道与重定向

管道是进程通信的方式,在脚本中使用是为了方便命令之间进行通信

管道符是“|”,将前一个命令执行的结果传递给后面的命令

示例
ls -l | more 组装多条命令, 实现分页显示
ps | cat
echo 123 | ps

重定向可以让程序输出到文件中,也可以将文件作为输入源

一个进程默认会打开标准输入0,标准输出1,错误输出2三个文件描述符

输入重定向符号 <

输出重定向符号>,>>,2>,&>, 共4种

输出时, >表示覆盖, >>表示追加, 2>表示只输出错误, &>表示无论正确与错误都进行输出

示例:
read var2 < a.txt 将a.txt输入到var2变量中
echo $var2 查看var2变量
echo $var2 > b.txt 将var2变量输出到b.txt中

输入输出可以组合使用, 一般用来在shell中生成新的文件
-------------------
#!/bin/bash
cat > /root/a.sh <<EOF
echo "hello world"
EOF
-------------------
执行上面脚本会生成a.sh文件, 文件中为 echo "hello world"

变量

  1. 变量名命名规则
  • 只能包含字母,数字,下划线
  • 不以数字开头
  1. 给变量赋值
  • 变量名=变量值, 如a=123, 注意等号两侧不能出现空格
  • 使用let为变量赋值, 如 let a=10-20
  • 将命令赋值给变量,如l=ls
  • 将命令结果赋值给变量,使用$()或者``, 如let c=$(ls -l /etc)
  • 变量值有空格等特殊字符可以包含在" "或者''中
  1. 变量的引用
- ${变量名}称作对变量的引用
- echo ${变量名}查看变量的值
- ${变量名}在部分情况下可以省略为 $变量名
  1. 变量的作用范围
  • 默认作用范围是当前shell
  • 变量的导出, 导出后子进程可以拿到父进程的变量
export 变量名
  • 变量的删除

unset 变量名

  1. 环境变量
bash
1.查看系统所有的环境变量
env | more

2.查看当前用户
echo $USER
echo $UID

3.查看命令搜索路径
echo $PATH
将/root添加到命令搜索路径
PATH=$PATH:/root

4.查看当前提示终端, 常用于增加终端提示信息,比如添加ip,时间等
echo $PS1
  1. 预定义变量
bash
确认上一条命令是否执行成功, 成功返回0,失败返回1
echo $?

显示当前进程的PID,常用于对脚本状态的监测
echo $$

显示当前进程的名称
echo $0

1745136084217 7. 位置变量, 用于脚本中定义变量, 外界传参

$1 $2...$9 ${10}...

示例脚本
--------
#!/bin/bash
echo $1
echo ${2-_}
--------
执行bash 1.sh test输出(${2}为空值时, 采用_)
test
_

环境变量的配置文件

bash
/etc下的是所有用户通用的配置文件, ~存放当前用户特有的配置文件

1. /etc/profile
当使用su - root,这个文件第一个被加载
系统环境环境变量和启动程序的环境变量,用于登陆配置
终端启动的时候的环境
不要在/etc/profile里面直接修改,而是创建一个custom.sh在/etc/profile.d里面制作自定义的修改

2. /etc/profile.d/
3. ~/.bash_profile
4. ~/.bashrc
5. /etc/bashrc

命令搜索路径增加新的路径, 将下面配置加到上面文件
export PATH=$PATH:/newPath...
添加后不会立即生效, 方式一是exit离开当前终端, 方式二是source /etc/profile(刚才改的配置文件)

切换root用户, 执行顺序如下: (这里为了测试依次在各个配置文件中加了echo 当前文件夹)

1745136094325 不加 - 登录时, 配置文件加载如下, 因此不建议使用这种登录方式

1745136101024

数组

1745136105934

bash
定义数组
TEST=(1 2 3)
显示数组的所有元素
echo ${TEST[@]}
显示数组元素个数
echo ${#TEST[@]}
显示数组的第一个元素
echo ${TEST[0]}

转义和引用

  • 特殊字符: 字符不仅有字面意义, 还有元意, 比如#注释 ;分号 \转义符号 "和'引号'
  • 单个字符前的转义符号, 比如 $, 将$转义成普通的符号
  • " 表示不完全引用, 变量的引用会被解释
  • ' 表示完全引用, 是啥就是啥
  • ` 反引号表示

运算符

  • 赋值运算符, 即 =
  • 基本运算符, - - * / ** %, 使用expr进行运算, 比如a=expr 4 - 5 (注意只能整数且中间要有空格)

数字常量的使用

let "变量名=变量值"

双圆括号是对let的简化:

(( a=10 ))

(( a-- ))

echo $(( 10-9 ))

特殊字符

引号

' ' 完全引用, 不会被赋值

"" 不完全引用, 会被赋值

` 执行命令, 等同于$()

括号

1745136114562

运算符号和逻辑符号

1745136123377

特殊符号

17451361273551745136131573

测试与判断

退出程序命令

- exit
- exit 10 返回10给Shell, 返回值非0位不正常退出
- $? 判断当前Shell前一个进程是否正常退出

test测试命令

  1. 注意在Shell脚本中, 0是真值, 非0是假值
  2. 对于Integer, 方括号不支持>, <, 应该使用[[ ]], 示例: [[ 5<4 ]]
  3. 英文字母区分大小写

1745136139438

if-then语句

语法如下:

bash
if [测试条件] 或命令
then 执行命令
elif [测试条件2]
then 执行命令
else 测试条件不成立, 执行相应命令
fi 结束

1745136144663174513614901517451361556541745136160318

分支

case

bash
case "$变量" in
	"情况1" )
 		命令...;;
  "情况2" )
  	命令...;;
  * )
  	命令...;;
esac

示例: 注意$0是当前脚本名字

1745136167042

循环

for循环

for 参数 in 列表
do 执行的命令
done 封闭一个循环
- 使用反引号或$()执行命令, 命令的结果当做列表进行处理
- 列表中包含多个变量, 变量用空格分隔
- 对文本处理, 要使用文本查看命令取出文本内容
- 默认逐行处理, 如果文本出现空格会当做多行处理

示例: 将*.mp3批量改为*.mp4

1745136173022

C语言风格的for

for((变量初始化;循环判断条件;变量变化))
do
	循环执行的命令
 done

1745136178380

while循环

bash
while test测试是否成立
do 
	命令
done

: 为空命令, while: ;为死循环

1745136182909

until循环

与while循环相反, 循环测试为假时, 执行循环, 为真时循环停止

循环的嵌套以及break, continue

break打破循环,

continue跳出当前循环

1745136187567

使用循环处理命令行参数

  • 命令行参数可以用$1 $2...${10}...$n来读取
  • $0代表脚本名称
  • $*和$@代表所有位置参数
  • $#代表位置参数的数量

示例: 将参数"help"打印两次

注意while循环中的shift作用是将参数左移, 比如sh test.sh a b c d 左移后参数剩 b c d

1745136192133

自定义函数

  • 自定义函数, function可省略
function fname(){

命令

}
  • 函数的执行

fname

  • 函数作用范围的变量

local 变量名

  • 函数的参数

$1 $2...$n

  • 函数的取消

unset fname

174513619821817451362018681745136208033

信号

kill会发送15号信号

ctrl-c会发送2号信号

示例: 使用trap捕获了15号以及2号信号, 因此此时使用kill或是ctrl-c不能使死循环停止 可以用kill -9 <pid>停止脚本, kill -9是不可阻塞的 1745136216690

计划任务

一次性计划任务

at命令

at 18:31
echo hello > /tmp/hello.txt

周期性计划任务

1745136222107