在前面的shell命令,环境变量,文本编辑等学习的基础上,可以开始shell脚本的探索之旅了。
要点一、基本脚本知识
- shell脚本的关键在于一次执行有序多个的命令。
1、脚本形式
(1)之前了解到的命令列表,即在命令行模式输入多个用分号;
分隔的命令实际上也算一种简单的脚本了;
(2)一般所指的脚本是将逐行书写的命令存储到文本文件中,即脚本文件。在需要运行这些命令时,只用运行这个文本文件就可以了。
尽管Linunx中文件名称不影响文件使用,但是我觉得自己在创建文件时还是加上熟悉的后缀,以便自己人为区别文件的类型。比如脚本文件的命名加上后缀名
.sh
。注意加不加这个后缀都对这个脚本没有任何影响。
2、脚本格式
- 第一行固定格式为
#!/bin/bash
,用于交代脚本所使用的shell类型。
这估计是
#
键最有存在感的一次,因为除此以外,其都是用作注释行用的。不过在脚本里,使用注释行是一种严谨的格式,以便之后帮助自己或别人理解此处命令的意义。
- 在第一行在之后逐行输入命令,直至结束即可。当然也可在一行里输入多个命令,用
;
分隔。
#!/bin/bash
#This is a test
date
who
3、运行脚本
要想成功运行脚本,并不是那么容易,要理解两个地方。
(1)command not found
test.sh
如果直接在命令行执行上述命令,会返回命令找不到。因为shell找不到该脚本。解决方法有二
- 一是将脚本所在的目录位置加入到PATH环境变量中,让系统自动查找该文件里的目录。不过单为了执行一个脚本而修改环境变量觉得也没必要;
- 二是采用全路径(绝对/相对)执行脚本命令。如果用户就在脚本所在目录,可以直接使用单点符
.
,快速执行。
(2)Permission denied
./test.sh
ls -lh test.sh
提示脚本不能执行的原因,往往是没有权限。与umask
默认值有关。比如Ubuntu系统默认为022,属主无执行权,此时可手动赋权
umask
chmod u+x test.sh
ls -lh test.sh
./test.sh
综上就可以执行脚本权限了。其实学到这里,脚本最基本的知识都已经知道了。但脚本强大、复杂的原因往往在于配合多种技巧的使用,接下来简单学习几种~
要点二、脚本技巧
1、echo 命令 “打印”文本
关于echo
命令的用法,直接在其后输入想“打印”的文本即可,无视空格;也可以用单/双引号划定文字字符串,尤其适用于字符串里已经含有引号时(此时两端加上另一种引号)
echo this is a test
echo "who're you"
- 在执行脚本时输出结果时,通过使用
echo
命令,添加解释性文本内容,不失为一种优雅的方法。
#!/bin/bash
echo They has logged into the system
who
echo -n "The time and date are: "
date
注意echo
命令的-n
参数可以将字符串和命令输出显示在同一行中,此时的字符串两端要加引号,且尾部要留有一个空格。
2、变量传递信息
关于变量要始终牢记:操作变量,不用加$
;使用变量要加$
。脚本中的变量主要有以下两种--
(1)系统全局变量(详见前面几节)
在脚本中都可以使用,set
命令会返回完整的当前环境变量列表,一般大写的均为系统全局变量。
#!/bin/bash
echo UID :$UID
echo HOME:$HOME
(2)用户定义局部变量
- 变量名可由字母(一般小写)、数字、下划线组成;
- 等号直接赋值,不要有空格;
- 赋值可以是数值、文本字符串;
var1=10
var2=-15
var3=test
var4="one two three"
- 变量的值也可以赋给另一个变量,巧妙地理解的
$
的使用时机
var5=$var1
- 变量的值也可以是命令的输出(命令替换)。有两种方法:反引号
``
与美元符配合括号$()
,感觉第二种要常用一些。
test1=`date`
test2=$(date)
一个常见的脚本示例如下
#!/bin/bash
today=$(date +%y%m%d) # +%y%m%将date输出格式改为两位数的年月日组合
ls /usr/bin -al > log.$today
目录中出现的日志文件采用的$today变量作为文件名的一部分。日志文件的内容是
usr/bin
目录内容的列表输出。
? 关于此处的子shell的交代?
- 最后注意一下作为脚本里的局部变量,脚本结束运行时,其会被自动删除。
3、重定向符号
(1)输出重定向
- 将命令的输出发送到一个文件中,一般为能够显示文本的命令,比如
ls
- 符号为大于号
>
date > test.txt
cat test.txt
注意如果此时当前目录已经存在test.txt文件,那么上述命令会覆盖掉原文件。如果想把命令输出的内容追加到原文件中,要使用双大于号>>
who >> test.txt
cat test.txt
(2)输入重定向
- 将文件的内容重定向到命令,一般为操作文本类命令,比如
sort
- 符号为小于号
<
wc < test.txt
wc
命令能够对文本内容分别计算行数、词数,字节数;
当然也有
<<
命令,叫内联输出重定向,详见p219
4、管道符号
上述的重定向>
与<
联用可以实现将命令的输出保存为文本,再输出给另一个命令。
cat /etc/passwd > tmp.txt
sort < tmp.txt
- 管道命令可以直接实现一个命令的输出作为另一个命令的输入;
- 符号为竖线符号
|
cat /etc/passwd | sort | more
如上,管道常用的方法就是将命令产生的大量输出通过管道传给more
命令,用以分屏显示。
5、数学计算器
- 早期,shell用的是
expr
命令,但比较麻烦,详见p224; - 后来在bash中,将一个数学运算结果赋给某个变量时,可以用美元符和方括号
$[]
将数学表达式框起来即可完成运算。(还记得$()
是什么意思吗~)
var1=$[1 + 5]
echo $var1
var2=$[$var1 * 5]
echo $var2
var3=$[$var1 * ($var2 - $var1)]
echo $var3
不过上述的用法只限于整数运算。若涉及到小数,可以考虑下面的bc
方法。
(1) bc基本用法
bc
如上在命令行输入bc
,首先会显示一段bc介绍信息(如果不想显示,可以加-q
参数),然后可以输入想计算的表达式,进行计算即可;最后输入quit
退出。不过,bc小数运算是由内建变量scale控制的,而其默认值为0,进行计算时需要设置下保留位数。
bc -q
12 * 5.4
64.8 #运算结果
3.2/5
0 #scale默认为0
scale=4
3.4/5
.6880 #返回四位小数
quit
结合教材的示例,我的理解是如果表达式里本身有小数存在,可以不用管(如 5-2.3);如果是计算产生的小数,需要设置scale值。(暂时没有条件可以演示...)
(2)脚本中的运算
- 使用
$()
命令替换,将运算命令的结果输入给变量; - 通过管道符号,利用
echo
命令,把scale值与运算式输给bc
命令
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5 " | bc)
echo The first answer is $var1
var2=100
var3=45
var4=$(echo "scale=3; $var2 / $var3 " | bc)
echo The second answer is $var4
6、退出状态码
(1)概念与用法
一般来说shell中的每个命令运行完毕后都会返回给shell一个退出状态码(exit status)。其由0~255的数字表示,储存在$?
变量里。一般来说,数字没有标准,但有一些可参考(详见p229):
-
0
命令成功结束; -
1
一般性未知错误; -
126
命令不可执行;
date
echo $? #返回0
sdcefdc
echo $? #返回127
(2)脚本退出状态码
- 默认情况下,shell脚本会以脚本中的最后一个命令的退出状态码退出;
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5 " | bc)
echo The first answer is $var1
exit $?
- 用
exit
命令可以认定脚本退出状态码的值
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5 " | bc)
echo The first answer is $var1
exit 10
昨晚真是糟糕透了。我一般是先大致在notepad里整理笔记,再写简书的。但是,今天电脑它,它卡住了......关机开机,半天笔记啥也没有了..啊啊啊。然后就是停课不停学的网课,慕课的平台,我真是无语了,又弄了好久。今天才总算完成这份笔记,噗~