本篇内容均摘自《Linux命令行与shell脚本编程大全》,个人认为需要重点学习的章节。【免费】Linux命令行与Shell脚本编程大全 第3版 PDF全本 21MB 百度网盘下载 - 今夕是何夕 - 博客园
重定向输入和输出
有些时候你想要保存某个命令的输出而不仅仅只是让它显示在显示器上。 bash shell提供了几个操作符,可以将命令的输出重定向到另一个位置(比如文件)。重定向可以用于输入,也可以用于输出,可以将文件重定向到命令输入。本节介绍了如何在shell脚本中使用重定向。
11.5.1 输出重定向
最基本的重定向将命令的输出发送到一个文件中。 bash shell用大于号( >)来完成这项功能:command > outputfile
之前显示器上出现的命令输出会被保存到指定的输出文件中。
$ date > test6
$ ls -l test6
-rw-r--r-- 1 user user 29 Feb 10 17:56 test6
$ cat test6
Thu Feb 10 17:56:58 EDT 2014
重定向操作符创建了一个文件test6(通过默认的umask设置),并将date命令的输出重定向到该文件中。如果输出文件已经存在了,重定向操作符会用新的文件数据覆盖已有文件。
$ who > test6
$ cat test6
user pts/0 Feb 10 17:55
现在test6文件的内容就是who命令的输出。有时,你可能并不想覆盖文件原有内容,而是想要将命令的输出追加到已有文件中,比如你正在创建一个记录系统上某个操作的日志文件。在这种情况下,可以用双大于号( >>)来追加数据。
$ date >> test6
$ cat test6
user pts/0 Feb 10 17:55
Thu Feb 10 18:02:14 EDT 2014
test6文件仍然包含早些时候who命令的数据,现在又加上了来自date命令的输出。
输入重定向
输入重定向和输出重定向正好相反。输入重定向将文件的内容重定向到命令,而非将命令的输出重定向到文件。输入重定向符号是小于号( <):
command < inputfile
一个简单的记忆方法就是:在命令行上,命令总是在左侧,而重定向符号“指向”数据流动的方向。小于号说明数据正在从输入文件流向命令。这里有个和wc命令一起使用输入重定向的例子。
$ wc < test6
2 11 60
wc命令可以对对数据中的文本进行计数。默认情况下,它会输出3个值:
1.文本的行数。2. 文本的词数。3.文本的字节数。
通过将文本文件重定向到wc命令,你立刻就可以得到文件中的行、词和字节的计数。这个例子说明test6文件有2行、 11个单词以及60字节。还有另外一种输入重定向的方法,称为内联输入重定向( inline input redirection)。这种方法无需使用文件进行重定向,只需要在命令行中指定用于输入重定向的数据就可以了。乍看一眼,这可能有点奇怪,但有些应用会用到这种方式(参见11.7节)。内联输入重定向符号是远小于号( <<)。除了这个符号,你必须指定一个文本标记来划分输入数据的开始和结尾。任何字符串都可作为文本标记,但在数据的开始和结尾文本标记必须一致。
command << marker
data
marker
在命令行上使用内联输入重定向时, shell会用PS2环境变量中定义的次提示符(参见第6章)来提示输入数据。下面是它的使用情况。
$ wc << EOF
> test string 1
> test string 2
> test string 3
> EOF
3 9 42
次提示符会持续提示,以获取更多的输入数据,直到你输入了作为文本标记的那个字符串。wc命令会对内联输入重定向提供的数据进行行、词和字节计数。
管道
和命令替换所用的反引号( `)一样,管道符号在shell编程之外也很少用到。该符号由两个竖线构成,一个在另一个上面。然而管道符号的印刷体通常看起来更像是单个竖线( |)。在美式键盘上,它通常和反斜线( \)位于同一个键。管道被放在命令之间,将一个命令的输出重定向到另一个命令中:
command1 | command2
不要以为由管道串起的两个命令会依次执行。 Linux系统实际上会同时运行这两个命令,在系统内部将它们连接起来。在第一个命令产生输出的同时,输出会被立即送给第二个命令。数据传输不会用到任何中间文件或缓冲区。例如:
$ rpm -qa | sort | more
这行命令序列会先执行rpm命令,将它的输出通过管道传给sort命令,然后再将sort的输出通过管道传给more命令来显示,在显示完一屏信息后停下来。到目前为止,管道最流行的用法之一是将命令产生的大量输出通过管道传送给more命令。ls -l命令产生了目录中所有文件的长列表。对包含大量文件的目录来说,这个列表会相当长。通过将输出管道连接到more命令,可以强制输出在一屏数据显示后停下来。
执行数学运算
在shell脚本中有两种途径来进行数学运算。
expr 命令
最开始, Bourne shell提供了一个特别的命令用来处理数学表达式。 expr命令允许在命令行上处理数学表达式,但是特别笨拙。
$ expr 1 + 5
6
(个人备注:实际上我试的时候1和+,还有5之间没有空格,输出来是以下的结果:)
expr 1+5
1+5
尽管标准操作符在expr命令中工作得很好,但在脚本或命令行上使用它们时仍有问题出现。许多expr命令操作符在shell中另有含义(比如星号)。当它们出现在在expr命令中时,会得到一些诡异的结果。
$ expr 5 * 2
expr: syntax error
要解决这个问题,对于那些容易被shell错误解释的字符,在它们传入expr命令之前,需要使用shell的转义字符(反斜线)将其标出来。
$ expr 5 \* 2
10
在shell脚本中使用expr命令也同样复杂:
$ cat test6
#!/bin/bash
# An example of using the expr command
var1=10
var2=20
var3=$(expr $var2 / $var1)
echo The result is $var3
要将一个数学算式的结果赋给一个变量,需要使用命令替换来获取expr命令的输出:
$ chmod u+x test6
$ ./test6
The result is 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
运行这个脚本会得到如下输出。
$ chmod u+x test7
$ ./test7
The final result is 500
同样,注意在使用方括号来计算公式时,不用担心shell会误解乘号或其他符号。 shell知道它不是通配符,因为它在方括号内。在bash shell脚本中进行算术运算会有一个主要的限制。请看下例:
$ cat test8
#!/bin/bash
var1=100
var2=45
var3=$[$var1 / $var2]
echo The final result is $var3
现在,运行一下,看看会发生什么:
$ chmod u+x test8
$ ./test8
The final result is 2
bash shell数学运算符只支持整数运算。若要进行任何实际的数学计算,这是一个巨大的限制。
浮点解决方案
有几种解决方案能够克服bash中数学运算的整数限制。最常见的方案是用内建的bash计算器,叫作bc。
- bc的基本用法
bash计算器实际上是一种编程语言,它允许在命令行中输入浮点表达式,然后解释并计算该表达式,最后返回结果。 bash计算器能够识别:数字(整数和浮点数),变量(简单变量和数组),注释(以#或C语言中的/* */开始的行),表达式,编程语句(例如if-then语句),函数。可以在shell提示符下通过bc命令访问bash计算器。要退出bash计算器,你必须输入quit。浮点运算是由内建变量scale控制的。必须将这个值设置为你希望在计算结果中保留的小数位数,否则无法得到期望的结果。
$ bc -q
3.44 / 5
0
scale=4
3.44 / 5
.6880
quit
scale变量的默认值是0。在scale值被设置前, bash计算器的计算结果不包含小数位。在将其值设置成4后, bash计算器显示的结果包含四位小数。 -q命令行选项可以不显示bash计算器冗长的欢迎信息。除了普通数字, bash计算器还能支持变量。
$ bc -q
var1=10
var1 * 4
40
var2 = var1 / 5
print var2
2
quit
变量一旦被定义,你就可以在整个bash计算器会话中使用该变量了。 print语句允许你打印变量和数字。
- 在脚本中使用bc
现在你可能想问bash计算器是如何在shell脚本中帮助处理浮点运算的。还记得命令替换吗?是的,可以用命令替换运行bc命令,并将输出赋给一个变量。基本格式如下:variable=$(echo "options; expression" | bc)。第一部分options允许你设置变量。如果你需要不止一个变量,可以用分号将其分开。expression参数定义了通过bc执行的数学表达式。这里有个在脚本中这么做的例子。
$ cat test9
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5" | bc)
echo The answer is $var1
这个例子将scale变量设置成了四位小数,并在expression部分指定了特定的运算。运行这个脚本会产生如下输出。
$ chmod u+x test9
$ ./test9
The answer is .6880
也可以用shell脚本中定义好的变量。
$ cat test10
#!/bin/bash
var1=100
var2=45
var3=$(echo "scale=4; $var1 / $var2" | bc)
echo The answer for this is $var3
脚本定义了两个变量,它们都可以用在expression部分,然后发送给bc命令。别忘了用美元符表示的是变量的值而不是变量自身。这个脚本的输出如下。
$ ./test10
The answer for this is 2.2222
当然,一旦变量被赋值,那个变量也可以用于其他运算。
$ cat test11
#!/bin/bash
var1=20
var2=3.14159
var3=$(echo "scale=4; $var1 * $var1" | bc)
var4=$(echo "scale=4; $var3 * $var2" | bc)
echo The final result is $var4
这个方法适用于较短的运算,但有时你会涉及更多的数字。如果需要进行大量运算,在一个命令行中列出多个表达式就会有点麻烦。有一个方法可以解决这个问题。 bc命令能识别输入重定向,允许你将一个文件重定向到bc命令来处理。但这同样会叫人头疼,因为你还得将表达式存放到文件中。最好的办法是使用内联输入重定向,它允许你直接在命令行中重定向数据。在shell脚本中,你可以将输出赋给一个变量。
variable=$(bc << EOF
options
statements
expressions
EOF
)
EOF文本字符串标识了内联重定向数据的起止。记住,仍然需要命令替换符号将bc命令的输赋给变量。现在可以将所有bash计算器涉及的部分都放到同一个脚本文件的不同行。下面是在脚本中使用这种技术的例子。
$ cat test12
#!/bin/bash
var1=10.46
var2=43.67
var3=33.2
var4=71
var5=$(bc << EOF
scale = 4
a1 = ( $var1 * $var2)
b1 = ($var3 * $var4)
a1 + b1
EOF
)
echo The final answer for this mess is $var5
将选项和表达式放在脚本的不同行中可以让处理过程变得更清晰,提高易读性。 EOF字符串标识了重定向给bc命令的数据的起止。 当然, 必须用命令替换符号标识出用来给变量赋值的命令。你还会注意到,在这个例子中,你可以在bash计算器中赋值给变量。这一点很重要:在bash计算器中创建的变量只在bash计算器中有效,不能在shell脚本中使用。