1.使用多个命令

shell允许只使用一步就将多个命令串联起来使用。如果要两个命令一起运行,可在同一提示行输入他们,用分号分隔开 ;

[xiaofei@DESKTOP-U55QOF8 ~]$date ; pwd
Sat Aug  4 15:51:12 DST 2018
/home/xiaofei

但是每次运行的时候都必须在命令提示符下输入整个命令。这样比较麻烦,所以我们可以将命令合并成一个简单的文本文件。要使用这些命令的时候,我只需要简单的运行这个文本文件。

2.创建shell脚本文件

在创建shell脚本文件时,必须在文件的第一行指定要使用的shell。其格式为:

#!/bin/bash

在通常的shell脚本中,井号(#)用作注释行。shell并不会处理shell脚本中的注释行。然而,shell脚本文件的第一行是个例外,#后面的惊叹号会告诉shell用哪个shell来运行脚本(是的,你可以使用bash shell,同时还可以使用另一个shell来运行你的脚本)。

在指定了shell之后,就可以在文件的每一行中输入命令,然后加一个回车符。

#!/bin/bash
# 注释信息
date
pwd

得到结果(有些时候可能会报错,可能是sh文件没有权限,需要用chmof 修改权限)

[xiaofei@DESKTOP-U55QOF8 shell]$sh 1.sh
Sun Aug  5 12:43:56 DST 2018
/mnt/d/shell
[xiaofei@DESKTOP-U55QOF8 shell]$./1.sh
Sun Aug  5 12:44:25 DST 2018
/mnt/d/shell

3.显示消息

大多数shell命令都会产生自己的输出,这些输出会显示在脚本所运行的控制台显示器上。很多时候,你可能想要添加自己的文本消息来告诉脚本用户脚本正在做什么。可以通过echo命令来实现这一点。如果在echo命令后面加上了一个字符串,该命令就能显示出这个文本字符串。

$ echo This is a test 
This is a test 

注意,默认情况下,不需要使用引号将要显示的文本字符串划定出来。但有时在字符串中出现引号的话就比较麻烦了。

$ echo Let's see if this'll work 
Lets see if thisll work

echo命令可用单引号或双引号来划定文本字符串。如果在字符串中用到了它们,你需要在文本中使用其中一种引号,而用另外一种来将字符串划定起来。

$ echo "This is a test to see if you're paying attention" 
This is a test to see if you're paying attention 
$ echo 'Rich says "scripting is easy".' 
Rich says "scripting is easy". 

所有的引号都可以正常输出了。
可以将echo语句添加到shell脚本中任何需要显示额外信息的地方。

#!/bin/bash
# 注释信息

echo The time and pwd are:
date
echo "where's file location:"
pwd

当运行这个脚本时,它会产生如下输出。

[xiaofei@DESKTOP-U55QOF8 shell]$sh 1.sh

The time and pwd are:
Sun Aug  5 12:55:22 DST 2018
where's file location:
/mnt/d/shell

但如果想把文本字符串和命令输出显示在同一行中,该怎么办呢?可以用echo语句的-n参数。只要将第一个echo语句改成这样就行(用处暂不太大):

echo -n "The time and date are: " 

需要在字符串的两侧使用引号,保证要显示的字符串尾部有一个空格。命令输出将会在紧接着字符串结束的地方出现。现在的输出会是这样:

$ ./test1 
The time and date are: Mon Feb 21 15:42:23 EST 2014 
Let's see who's logged into the system: 
Christine tty2         2014-02-21 15:26 
Samantha tty3         2014-02-21 15:26 
Timothy  tty1         2014-02-21 15:26 
user     tty7         2014-02-19 14:03 (:0) 
user     pts/0        2014-02-21 15:21 (:0.0) 

4.使用变量

运行shell脚本中的单个命令自然有用,但这有其自身的限制。通常你会需要在shell命令使用其他数据来处理信息。这可以通过变量来实现。变量允许你临时性地将信息存储在shell脚本中,以便和脚本中的其他命令一起使用。本节将介绍如何在shell脚本中使用变量。

4.1 环境变量

在脚本中,你可以在环境变量名称之前加上美元符($)来使用这些环境变量。下面的脚本演示了这种用法。

#!/bin/bash
# 注释信息

echo "User info for userid: $USER"
echo UID: $UID
echo HOME: $HOME

USERUSER、UID和$HOME环境变量用来显示已登录用户的有关信息。脚本输出如下:

[xiaofei@DESKTOP-U55QOF8 shell]$sh 2.sh
User info for userid: xiaofei
UID:
HOME: /home/xiaofei

注意,echo命令中的环境变量会在脚本运行时替换成当前值。另外,在第一个字符串中可以将$USER系统变量放置到双引号中,而shell依然能够知道我们的意图。但采用这种方法也有一个问题。看看下面这个例子会怎么样。

$ echo "The cost of the item is $15" 
The cost of the item is 5 

显然这不是我们想要的。只要脚本在引号中出现美元符,它就会以为你在引用一个变量。在这个例子中,脚本会尝试显示变量$1(但并未定义),再显示数字5。要显示美元符,你必须在它前面放置一个反斜线。

$ echo "The cost of the item is \$15" 
The cost of the item is $15 

看起来好多了。反斜线允许shell脚本将美元符解读为实际的美元符,而不是变量。

4.2 用户变量

除了环境变量,shell脚本还允许在脚本中定义和使用自己的变量。定义变量允许临时存储数据并在整个脚本中使用,从而使shell脚本看起来更像一个真正的计算机程序。

用户变量可以是任何由字母、数字或下划线组成的文本字符串,长度不超过20个。用户变量区分大小写,所以变量Var1和变量var1是不同的。
使用等号将值赋给用户变量。在变量、等号和值之间不能出现空格。
赋值例子:

var1=10 
var2=-57 
var3=testing 
var4="still more testing" 

shell脚本会自动决定变量值的数据类型。在脚本的整个生命周期里,shell脚本中定义的变量会一直保持着它们的值,但在shell脚本结束时会被删除掉。
与系统变量类似,用户变量可通过美元符引用。

$ cat test3.sh
#!/bin/bash 
# testing variables 
days=10 
guest="Katie" 
echo "$guest checked in $days days ago" 
days=5 
guest="Jessica" 
echo "$guest checked in $days days ago"

运行脚本会有如下输出。

[xiaofei@DESKTOP-U55QOF8 shell]$sh test3.sh
Katie checked in 10 days ago
Jessica checked in 5 days ago

变量每次被引用时,都会输出当前赋给它的值。重要的是要记住,引用一个变量值时需要使用美元符,而引用变量来对其进行赋值时则不要使用美元符。通过一个例子你就能明白意思。

$ cat test4.sh
#!/bin/bash 
# assigning a variable value to another variable 
 
value1=10 
value2=$value1 
echo The resulting value is $value2

在赋值语句中使用value1变量的值时,仍然必须用美元符。这段代码产生如下输出。

$sh test4.sh 
The resulting value is 10 

要是忘了用美元符,使得value2的赋值行变成了这样:

value2=value1 

那你会得到如下输出:

$sh test4.sh 
The resulting value is value1 

没有美元符,shell会将变量名解释成普通的文本字符串,通常这并不是你想要的结果。

4.3 命令替换

shell脚本中最有用的特性之一就是可以从命令输出中提取信息,并将其赋给变量。把输出赋给变量之后,就可以随意在脚本中使用了。这个特性在处理脚本数据时尤为方便。

有两种方法可以将命令输出赋给变量:

  • 反引号字符 (`)
  • $() 格式

要注意反引号字符,这可不是用于字符串的那个普通的单引号字符。由于在shell脚本之外很少用到,你可能甚至都不知道在键盘什么地方能找到这个字符。但你必须慢慢熟悉它,因为这是许多shell脚本中的重要组件。提示:在美式键盘上,它通常和波浪线(~)位于同一键位。

命令替换允许你将shell命令的输出赋给变量。尽管这看起来并不那么重要,但它却是脚本编程中的一个主要组成部分。

要么用一对反引号把整个命令行命令围起来:

testing='date' 

要么使用$()格式:

testing=$(date)

shell会运行命令替换符号中的命令,并将其输出赋给变量testing。注意,赋值等号和命令替换字符之间没有空格。这里有个使用普通的shell命令输出创建变量的例子。

$ cat test5.sh 
#!/bin/bash 
testing=$(date) 
echo "The date and time are: " $testing

变量testing获得了date命令的输出,然后使用echo语句显示出它的值。运行这个shell脚本生成如下输出。

$sh test5.sh
The date and time are:  Mon Aug 6 15:05:40 DST 2018

下面这个例子很常见,它在脚本中通过命令替换获得当前日期并用它来生成唯一文件名。

#!/bin/bash 
# copy the /usr/bin directory listing to a log file 
today=$(date +%y%m%d) 
ls /usr/bin -al > log.$today 

today变量是被赋予格式化后的date命令的输出。这是提取日期信息来生成日志文件名常用的一种技术。+%y%m%d格式告诉date命令将日期显示为两位数的年月日的组合。

$date +%y%m%d
180806

这个脚本将日期值赋给一个变量,之后再将其作为文件名的一部分。文件自身含有目录列表的重定向输出。运行该脚本之后,应该能在目录中看到一个新文件。

目录中出现的日志文件采用$today变量的值作为文件名的一部分。日志文件的内容是/usr/bin目录内容的列表输出。如果脚本在明天运行,日志文件名会是log.140201,就这样为新的一天创建一个新文件。

5.重定向输入和输出

有些时候你想要保存某个命令的输出而不仅仅只是让它显示在显示器上。bash shell提供了几个操作符,可以将命令的输出重定向到另一个位置(比如文件)。重定向可以用于输入,也可以用于输出,可以将文件重定向到命令输入。本节介绍了如何在shell脚本中使用重定向。

5.1输出重定向

最基本的重定向将命令的输出发送到一个文件中。bash shell用大于号(>)来完成这项功能:

command > outputfile

如果输出文件已经存在了,重定向操作符会用新的文件数据覆盖已有文件。
有时,你可能并不想覆盖文件原有内容,而是想要将命令的输出追加到已有文件中,比如你正在创建一个记录系统上某个操作的日志文件。在这种情况下,可以用双大于号(>>)来追加数据。

5.2输入重定向

输入重定向和输出重定向正好相反。输入重定向将文件的内容重定向到命令,而非将命令的输出重定向到文件。

输入重定向符号是小于号(<):

command < outputfile

一个简单的记忆方法就是:在命令行上,命令总是在左侧,而重定向符号“指向”数据流动的方向。小于号说明数据正在从输入文件流向命令。
这里有个和wc命令一起使用输入重定向的例子。

$ wc < test6 
      2      11      60

wc命令可以对对数据中的文本进行计数。默认情况下,它会输出3个值:
 文本的行数
 文本的词数
 文本的字节数

通过将文本文件重定向到wc命令,你立刻就可以得到文件中的行、词和字节的计数。这个例子说明test6文件有2行、11个单词以及60字节。


这个暂时不知道怎么用,先放着

还有另外一种输入重定向的方法,称为内联输入重定向(inline input redirection)。这种方法无需使用文件进行重定向,只需要在命令行中指定用于输入重定向的数据就可以了。乍看一眼,这可能有点奇怪,但有些应用会用到这种方式


6.管道

有时需要将一个命令的输出作为另一个命令的输入。

在美式键盘上,它通常和反斜线(\)位于同一个键。管道被放在命令之间,将一个命令的输出重定向到另一个命令中:

command1 | command2 

不要以为由管道串起的两个命令会依次执行。Linux系统实际上会同时运行这两个命令,在系统内部将它们连接起来。在第一个命令产生输出的同时,输出会被立即送给第二个命令。数据传输不会用到任何中间文件或缓冲区。

7.执行数学运算

另一个对任何编程语言都很重要的特性是操作数字的能力。遗憾的是,对shell脚本来说,这个处理过程会比较麻烦。在shell脚本中有两种途径来进行数学运算。

7.1 expr命令

最开始,Bourne shell提供了一个特别的命令用来处理数学表达式。expr命令允许在命令行上处理数学表达式,但是特别笨拙。

$ expr 1 + 5 
6 

不常见。不详述!

7.2 使用方括号

bash shell为了保持跟Bourne shell的兼容而包含了expr命令,但它同样也提供了一种更简单的方法来执行数学表达式。在bash中,在将一个数学运算结果赋给某个变量时,可以用美元符和方括号($[ operation ])将数学表达式围起来。

$ var1=$[1 + 5] 
$ echo $var1 
6 
$ var2=$[$var1 * 2] 
$ echo $var2 
12 

用方括号执行shell数学运算比用expr命令方便很多。这种技术也适用于shell脚本。

$ cat test7 
#!/bin/bash 
var1=100 
var2=50 
var3=45 
var4=$[$var1 * ($var2 - $var3)] 
echo The final result is $var4

同样,注意在使用方括号来计算公式时,不用担心shell会误解乘号或其他符号。shell知道它不是通配符,因为它在方括号内.

在bash shell脚本中进行算术运算会有一个主要的限制,bash shell数学运算符只支持整数运算。若要进行任何实际的数学计算,这是一个巨大的限制。

7.3 浮点解决方案

有几种解决方案能够克服bash中数学运算的整数限制。最常见的方案是用内建的bash计算器,叫作bc。
暂不详解!!

8.退出脚本

暂不详解!!

9.小结

bash shell脚本允许你将多个命令串起来放进脚本中。创建脚本的最基本的方式是将命令行中的多个命令通过分号分开来。shell会按顺序逐个执行命令,在显示器上显示每个命令的输出。

你也可以创建一个shell脚本文件,将多个命令放进同一个文件,让shell依次执行。shell脚本文件必须定义用于运行脚本的shell。这个可以通过#!符号在脚本文件的第一行指定,后面跟上shell的完整路径。

在shell脚本内,你可以通过在变量前使用美元符来引用环境变量。也可以定义自己的变量以便在脚本内使用,并对其赋值,甚至还可以通过反引号或$()捕获的某个命令的输出。在脚本中可以通过在变量名前放置一个美元符来使用变量的值。

bash shell允许你更改命令的标准输入和输出,将其重定向到其他地方。你可以通过大于号将命令输出从显示器屏幕重定向到一个文件中。也可以通过双大于号将输出数据追加到已有文件。小于号用来将输入重定向到命令。你可以将文件内容重定向到某个命令。
Linux管道命令(断条符号)允许你将命令的输出直接重定向到另一个命令的输入。Linux系统能够同时运行这两条命令,将第一个命令的输出发送给第二个命令的输入,不需要借助任何重定向文件。
bash shell提供了多种方式在shell脚本中执行数学操作。expr命令是一种进行整数运算的简便方法。在bash shell中,你也可以通过将美元符号放在由方括号包围的表达式之前来执行基本的数学运算。为了执行浮点运算,你需要利用bc计算器命令,将内联数据重定向到输入,然后将输出存储到用户变量中。

最后,本章讨论了如何在shell脚本中使用退出状态码。shell中运行的每个命令都会产生一个退出状态码。退出状态码是一个0~255的整数值,表明命令是否成功执行;如果没有成功,可能的原因是什么。退出状态码0表明命令成功执行了。你可以在shell脚本中用exit命令来声明一个脚本完成时的退出状态码。

到目前为止,脚本中的命令都是按照有序的方式一个接着一个处理的。在下章中,你将学习如何用一些逻辑流程控制来更改命令的执行次序。