随堂练习 shell脚本

Posted 空白的Melody

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了随堂练习 shell脚本相关的知识,希望对你有一定的参考价值。

第一步:使用文本编辑器来创建文本文件

第一行:必须包括shell 声明序列:#!

示例:#!/bin/bash

第二步:加执行权限

给予执行权限,在命令行上指定脚本的绝对或相对路径

第三步:运行脚本

直接运行解释器,将脚本作为解释器程序的参数运行

范例:第一个shell 脚本 hello world

#!/bin/bash

echo "Hello,world!"

执行:

bash hell.sh

shell 脚本调试

只检测脚本中的语法错误,但无法检查出命令错误,但不真正执行脚本

bash -n /path/some_script.sh

调试并执行

bash  -x /path/some_script.sh

 

cat -A test.sh

#!/bin/bash

echo line1$

hostnam$
cat > test.txt <<EOF $
aaa$
bbb$
ccc$
EOF $
$
echo line22$
[root@centos8 scripts]#bash -n test.sh
f1.sh: line 20: warning: here-document at line 14 delimited by end-of-file
(wanted `EOF\')

总结:脚本错误常见的有三种

1)语法错误。会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准确的

2)命令错误。默认后续的命令还会继续执行,用bash -n 无法检查出来,可以使用 bash -x 进行观察

3)逻辑错误。只能使用 bash -x 进行观察

1,变量

变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据

2,变量类型

1)内置变量:如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE

2)用户自定义变量

不同的变量存放的数据不同,决定了以下

  1)数据存储方式

  2)参与的运算

  3)表示的数据范围

变量数据类型

  字符

  数值:整型,浮点型,bash不支持浮点数

静态和动态语言

  1)静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c

  2)动态编译语言:不用事先声明,可随时改变类型,如:bash,Python

强类型和弱类型语言

  1)强类型语言:不同类型数据操作,必须经过强制转换才同一类型才能运算,如:java,c#,Python

  如:参考以下Python代码

    print(\'long\'+10) 提示出错,不会自动转换类型

    print(\'long\'+str(10)) 结果为long10,需要显示转换类型

  2)弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用。如:bash,phpjavascript

3,shell 中变量命名法则

1)不能使用程序中的保留字:如 :if,for等

2)只能使用数字,字母及下划线,且不能以数字开头,注意:不支持短横线“-”,和主机名相反

3)见名知意,用英文单词命名,并体现出实际作用,不要用简写, 如:ATM

4)统一命名规则:驼峰命名法;大驼峰 StudentName,小驼峰studentName

5)变量名大写:STUDENT_NAME

6)局部变量小写

7)函数名小写

4,变量的生效范围等标准划分变量类型

  1)普通变量:生效范围为当前shell 进程;对当前shell 之外的其它shell 进程,包括当前shell 的子shell 进程均无效

  2)环境变量:生效范围为当前shell 进程及其子进程

  3)本地变量:生效范围为当前shell 进程中某代码片断,通常指函数

变量赋值

name=\'value\'

value 可以是以下多种形式

直接字串:name=\'root\'

变量引用:name=\'$USER\'

命令引用:name=`COMMAND`  或  name=$(COMMAND)

注意:变量赋值是临时生效。当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除

变量引用:

$name

${name}

弱引用和强引用

1)"$name" 弱引用,其中的变量引用会被替换为变量值

2)\'$name\'  强引用,其中的变量引用不会被替换为变量值,而保持原字符串

范例:变量的各种赋值方式和引用

[root@centos8 ~]#TITLE=\'cto\'
[root@centos8 ~]#echo $TITLE
cto
[root@centos8 ~]#echo I am $TITLE
I am cto
[root@centos8 ~]#echo "I am $TITLE"
I am cto
[root@centos8 ~]#echo \'I am $TITLE\'
I am $TITLE
[root@centos8 ~]#NAME=$USER
[root@centos8 ~]#echo $NAME
root
[root@centos8 ~]#USER=`whoami`
[root@centos8 ~]#echo $USER
root

[root@centos8 ~]#FILE=/etc/*
[root@centos8 ~]#echo $FILE
/etc/adjtime /etc/aliases /etc/alternatives /etc/anacrontab /etc/at.deny
/etc/audit /etc/authselect /etc/autofs.conf /etc/autofs_ldap_auth.conf
[root@centos8 ~]#seq 10
1
2
3
4
5
6
7
8
9
10
[root@centos8 ~]#NUM=`seq 10`
[root@centos8 ~]#echo $NUM
1 2 3 4 5 6 7 8 9 10

[root@centos8 ~]#NAMES="wang
> zhang
> zhao
> li"
[root@centos8 ~]#echo $NAMES
wang zhang zhao li
[root@centos8 ~]#echo "$NAMES"
wang
zhang
zhao
li

 

范例:变量引用

[root@centos8 data]#NAME=long
[root@centos8 data]#AGE=20
[root@centos8 data]#echo $NAME
long
[root@centos8 data]#echo $AGE
20
[root@centos8 data]#echo $NAME $AGE
long 20
[root@centos8 data]#echo $NAME$AGE
long20
[root@centos8 data]#echo $NAME_$AGE
20

[root@centos8 data]#echo ${NAME}_$AGE
long_20

 

范例:变量的间接赋值和引用

[root@centos8 ~]#TITLE=cto
[root@centos8 ~]#NAME=wang
[root@centos8 ~]#TITLE=$NAME
[root@centos8 ~]#echo $NAME
wang
[root@centos8 ~]#echo $TITLE
wang
[root@centos8 ~]#NAME=long
[root@centos8 ~]#echo $NAME
long
[root@centos8 ~]#echo $TITLE
wang

范例:变量追加值

[root@centos8 ~]#TITLE=CTO
[root@centos8 ~]#TITLE+=:wang
[root@centos8 ~]#echo $TITLE
CTO:wang

范例:利用变量实现动态命令

[root@centos8 ~]#CMD=hostname
[root@centos8 ~]#$CMD
centos8.longwang.com

显示已定义的所有变量:set

删除变量:unset <name>

[root@centos8 ~]#NAME=long

[root@centos8 ~]#TITLE=ceo
[root@centos8 ~]#echo $NAME $TITLE
long ceo
[root@centos8 ~]#unset NAME TITLE
[root@centos8 ~]#echo $NAME $TITLE

范例:显示系统信息

#!/bin/bash
#
#********************************************************************
#Author: xuanlv
#QQ: 360956175
#Date: 2020-06-15
#FileName: system_info.sh
#URL: http://www
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
RED="\\E[1;31m"
GREEN="echo -e \\E[1;32m"
END="\\E[0m"
$GREEN-----------------------Host systeminfo-----------------------$END
echo -e "HOSTNAME: $RED`hostname`$END"
echo -e "IPADDR: $RED`ifconfig eth0 |grep -Eo \'([0-9]{1,3}\\.){3}[0-9]{1,3}\' |head -n1`$END "
echo -e "OSVERSION: $RED`cat /etc/redhat-release`$END"
echo -e "KERNEL: $RED`uname -r`$END"
echo -e "CPU: $RED`lscpu |grep \'Model name\' |tr -s \' \' |cut -d: -f2`$END"
echo -e "MEMORY: $RED`free -h |grep Mem |tr -s \' \' : |cut -d: -f2`$END"
echo -e "DISK: $RED`lsblk |grep \'^nv\' |tr -s \' \' |cut -d " " -f4`$END"
$GREEN------------------------------------------------------------$END

 

 

 5,环境变量

  1)可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量

  2)一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程

  3)一般只在系统配置文件中使用,在脚本中较少使用

变量声明和赋值

#声明并赋值
export name=VALUE
declare -x name=VALUE
#或者分两步实现
name=VALUE
export name

显示所有环节变量

env

printenv

export

declare -x

bash 内建的环境变量

PATH

SHELL

USER

UID

HOME

PWD

SHLVL  # shell 的嵌套层数,即深度

LANG

MAIL

HOSTNAME

HISTIZE

_     # 下划线   表示前一个命令的最后一个参数

只读变量:只能声明定义,但后续不能修改和删除,即常量

声明只读变量:

readonly  name

declare  -r name

查看只读变量

readonly  [-p]

declare  -r

[root@centos8 ~]#readonly PI=3.14159
[root@centos8 ~]#echo $PI
3.14159
[root@centos8 ~]#PI=3.14
-bash: PI: readonly variable
[root@centos8 ~]#unset PI
-bash: unset: PI: cannot unset: readonly variable
[root@centos8 ~]#echo $PI
3.14159
[root@centos8 ~]#exit
logout

6,位置变量

位置变量:在bash shell 中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数

$1,$2,... 对应第1个,第2个等参数, shift [n]换位置

$0  命令本身,包括路径

$*  传递给脚本的所有参数,全部参数合为一个字符串

$@  传递给脚本的所有参数,每个参数为独立字符串

$#  传递给脚本的参数的个数

注意:$@   $*   只在被双引号包起来的时候才会有差异

清空所有位置变量

set  --

[root@centos8 ~]#cat /data/scripts/arg.sh
#!/bin/bash
#
#********************************************************************
#Author: xuanlv
#QQ: 360956175
#Date: 2020-06-20
#FileName: arg.sh
#URL: http://www.
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
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@centos8 ~]#bash /data/scripts/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

 

介绍下Shell中的${}、##和%%使用范例,本文给出了不同情况下得到的结果。
 
假设定义了一个变量为:
 
代码如下:
 
file=/dir1/dir2/dir3/my.file.txt
 
可以用${ }分别替换得到不同的值:
 
${file#*/}:删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
 
${file##*/}:删掉最后一个 / 及其左边的字符串:my.file.txt
 
${file#*.}:删掉第一个 . 及其左边的字符串:file.txt
 
${file##*.}:删掉最后一个 . 及其左边的字符串:txt
 
${file%/*}:删掉最后一个 / 及其右边的字符串:/dir1/dir2/dir3
 
${file%%/*}:删掉第一个 / 及其右边的字符串:(空值)
 
${file%.*}:删掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
 
${file%%.*}:删掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
 
记忆的方法为:
 
# 是 去掉左边(键盘上#在 $ 的左边)
 
%是去掉右边(键盘上% 在$ 的右边)
 
单一符号是最小匹配;两个符号是最大匹配
 
${file:0:5}:提取最左边的 5 个字节:/dir1
 
${file:5:5}:提取第 5 个字节右边的连续5个字节:/dir2
 
也可以对变量值里的字符串作替换:
 
${file/dir/path}:将第一个dir 替换为path:/path1/dir2/dir3/my.file.txt
 
${file//dir/path}:将全部dir 替换为 path:/path1/path2/path3/my.file.txt

范例:删库跑路之命令rm的安全实现

#!/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@centos8 ~]#chmod a+x /data/scripts/rm.sh
[root@centos8 ~]#alias rm=\'/data/scripts/rm.sh\'
[root@centos8 ~]#touch {1..10}.txt
[root@centos8 ~]#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-
06-20_15-15-28

范例:$* 和$@ 的区别

[root@centos8 scripts]#cat f1.sh
#!/bin/bash
echo "f1.sh:all args are $@"
echo "f1.sh:all args are $*"
./file.sh "$*"
[root@centos8 scripts]#cat f2.sh
#!/bin/bash
echo "f2.sh:all args are $@"
echo "f2.sh:all args are $*"

./file.sh "$@"
[root@centos8 scripts]#cat file.sh
#!/bin/bash
echo "file.sh:1st arg is $1"
[root@centos8 scripts]#./f1.sh a b c
f1.sh:all args are a b c
f1.sh:all args are a b c
file.sh:1st arg is a b c
[root@centos8 scripts]#./f2.sh a b c
f2.sh:all args are a b c
f2.sh:all args are a b c
file.sh:1st arg is a

范例: 利用软链接实现同一个脚本不同功能

[root@centos8 ~]#cat test.sh
#!/bin/bash
#********************************************************************
echo $0
[root@centos8 ~]#ln -s test.sh a.sh
[root@centos8 ~]#ln -s test.sh b.sh
[root@centos8 ~]#./a.sh
./a.sh
[root@centos8 ~]#./b.sh
./b.sh

 

7,退出状态码变量

进程执行后,将使用变量$? 保存状态码的相关数字,不同的值反应成功或失败,

$?  的值为 0           # 代表成功

$?  的值是1 到 255   # 代表失败

用户可以在脚本中使用以下命令自定义退出状态码

exit  [n]

注意:

1)脚本中一旦遇到exit 命令,脚本会立即终止;终止退出状态取决于 exit 命令后的数字

2)如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

8,展开命令执行顺序

把命令行分成单个命令词

展开别名

展开大括号的声明 {}

展开波浪符声明 ~

命令替换 $() 和 ``

再次把命令行分成命令词

展开文件通配*,?,[abc]等等

准备I/O重定向 < ,>

运行命令

防止扩展

反斜线 (\\)会使随后的字符按原意解释

范例:

echo Your cost: \\$5.00
Your cost: $5.00

加引号来防止扩展

单引号(\' \')防止所有扩展

双引号(" ")也可防止扩展,但是以下情况例外:$(美元符号)

变量扩展

``  :反引号,命令替换

\\  :反斜线,禁止单个字符扩展

:叹号,历史命令替换

脚本安全和 set

$- 变量
h:hashall,打开选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选
项关闭
i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的 shell。所谓的交互式shell,
在脚本中,i选项是关闭的
m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等
B:braceexpand,大括号扩展
H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的
一个历史命令,“!n”返回第 n 个历史命令

范例:

[root@centos8 ~]#echo $-
himBHs
[root@centos8 ~]#set +h
[root@centos8 ~]#echo $-
imBHs
[root@centos8 ~]#hash
-bash: hash: hashing disabled
[root@centos8 ~]#echo {1..10}
1 2 3 4 5 6 7 8 9 10
[root@centos8 ~]#echo $-
imBHs
[root@centos8 ~]#set +B
[root@centos8 ~]#echo $-
imHs
[root@centos8 ~]#echo {1..10}
{1..10}

set 命令实现脚本安全

-u  :在扩展一个没有设置的变量时,显示错误信息,等同set -o  nounset

-e  :如果一个命令返回一个非0 退出状态值(失败)就退出,等同 set -o errexit

-o  :option 显示,打开或者关闭选项

  显示选项:set -o

  打开选项:set -o 选项

  关闭选项:set +o 选项

-x  :当执行命令时,打印命令及其参数,类似 bash -x

9,格式化输出 printf

格式:printf "指定的格式"  "文本1" "文本2"...

 

 

 常用格式替换符

替换符: 功能

%s :字符串

%f  :浮点格式

%b :相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义

%c :ASCII字符,即显示对应参数的第一个字符

%d,%i :十进制整数

%o :八进制值

%u :不带正负号的十进制值

%x :十六进制值(a-f)

%X :十六进制值(A-F)

%% :表示% 本身

说明:%s 中的数字代表此替换符中的输出字符宽度,不足补空格,默认是右对齐,%-10s表示10个字
符宽,- 表示左对齐

常用转义字符:

转义符: 功能

\\a  :警告字符,通常为ASCII 的BEL字符

\\b  :后退

\\f  :换页

\\n :换行

\\r :回车

\\t :水平制表符

\\v :垂直制表符

\\  :表示 \\ 本身

范例:

[root@centos8 ~]#printf "%s\\n" 1 2 3 4
1
2
3
4
[root@centos8 ~]#printf "%s %s \\n" 1 2 3 4
1 2
3 4

[root@centos8 ~]#printf "%f\\n" 1 2 3 4
1.000000
2.000000
3.000000
4.000000
#.2f 表示保留两位小数
[root@centos8 ~]#printf "%.2f\\n" 1 2 3 4
1.00
2.00
3.00
4.00
[root@centos8 ~]#printf "(%s)" 1 2 3 4;echo
(1)(2)(3)(4)
[root@centos8 ~]#printf " (%s) " 1 2 3 4;echo ""
(1) (2) (3) (4)
[root@centos8 ~]#printf "(%s)\\n" 1 2 3 4
(1)
(2)
(3)
(4)
[root@centos8 ~]#printf "%s %s\\n" 1 2 3 4
1 2
3 4
[root@centos8 ~]#printf "%s %s %s\\n" 1 2 3 4
1 2 3
4

#%-10s 表示宽度10个字符,左对齐

[root@centos8 ~]#printf "%-10s %-10s %-4s %s \\n" 姓名 性别 年龄 体重 小明 男 20 70小红 女 18 50

姓名 性别 年龄 体重
小明 男 20 70
小红 女 18 50
#将十进制的17转换成16进制数
[root@centos8 ~]#printf "%X" 17
11

[root@centos8 ~]#
#将十六进制C转换成十进制
[root@centos8 ~]#printf "%d\\n" 0xC
12
[root@centos8 ~]#VAR="welcome to dd";printf "\\033[1;31m%s\\033[0m\\n" $VAR
welcome
to
dd
[root@centos8 ~]#VAR="welcome to dd";printf "\\033[1;31m%s\\033[0m\\n" "$VAR"
welcome to dd

以上是关于随堂练习 shell脚本的主要内容,如果未能解决你的问题,请参考以下文章

随堂练习 shell脚本

随堂练习 bash shell特性和I/O重定向及管道

7个shell脚本实例--shell脚本练习必备

Shell脚本练习

shell脚本练习实例详解

shell脚本练习