当前位置:   article > 正文

Linux命令行与shell脚本编程大全-2.1

Linux命令行与shell脚本编程大全-2.1

第二部分 shell脚本编程基础

第11章构建基础脚本
第12章结构化命令
第13章更多的结构化命令
第14章处理用户输入
第15章呈现数据
第16章脚本控制

第11章构建基础脚本

11.1 使用多个命令

让两个命令一起运行,可以将其放在同一行中,彼此用分号隔开

$ date ; who

11.2 创建shell脚本文件

在创建shell 脚本文件时,必须在文件的第一行指定要使用的shell,格式如下:
#!/bin/bash

在普通的shell 脚本中,#用作注释行,#后面的惊叹号会告诉shell 用哪个shell 来运行脚本。

PATH 环境变量被设置为用于在其中查找命令的一系列目录。采用下列两种方法之一:

  •  将放置shell 脚本文件的目录添加到PATH 环境变量中;
  • 在命令行中使用绝对路径或相对路径来引用shell 脚本文件。

11.3 显示消息:echo

$ echo "This is a test to see if you're paying attention"

$ cat test1
#!/bin/bash
# This script displays the date and who's logged on
echo The time and date are:
date
echo "Let's see who's logged into the system: "
who
$

11.4 使用变量

11.4.1环境变量

用set 命令显示一份完整的当前环境变量列表

在脚本中,可以在环境变量名之前加上$来引用这些环境变量

11.4.2用户自定义变量

用户自定义变量可以通过$引用

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

11.4.3 命令替换

有两种方法可以将命令输出赋给变量
反引号(`)
$()格式

$ cat test5
#!/bin/bash
testing=$(date)
echo "The date and time are: " $testing
$
变量testing 保存着date 命令的输出,然后会使用echo 命令显示出该变量的值。

11.5 重定向输入和输出

11.5.1 输出重定向

最基本的重定向会将命令的输出发送至文件。bash shell 使用大于号(>)来实现该操作。如果输出文件已存在,则重定向运算符会用新数据覆盖已有的文件

$ date > test6

不想覆盖文件原有内容,而是想将命令输出追加到已有文件中,可以用双大于号(>>)来追加数据

$ date >> test6

11.5.2 输入重定向

输入重定向会将文件的内容重定向至命令,而不是将命令输出重定向至文件。

输入重定向运算符是小于号(<):command < inputfile

wc 命令可以统计数据中的文本。在默认情况下,它会输出3 个值

文本的行数
文本的单词数
文本的字节数

11.6 管道

需要将一个命令的输出作为另一个命令的输入,无须将命令输出重定向至文件,可以将其直接传给另一个命令。这个过程称为管道连接(piping),单个竖线(|)来实现该操作,管道可以串联的命令数量没有限制。可以持续地将命令输出通过管道传给其他命令来细化
操作。

$ rpm -qa | sort | more
这行命令序列会执行rpm 命令,将其输出通过管道传给sort 命令,然后再将sort 的输出
通过管道传给more 命令来显示,在显示完一屏信息后暂停。

11.7 执行数学运算

编程语言的另一项至关重要的特性是数学运算能力

11.7.1 expr命令

门用于处理数学表达式的命令:expr,该命令可在命令行中执行数学运算,但是特别笨拙。

$ expr 1 + 5

11.7.2使用方括号

许多expr 命令运算符在shell 中另有他意(比如*)此时需要使用方括号。在使用方括号执行数学运算时,无须担心shell 会误解乘号或其他符号。shell 清楚方括号内的星号不是通配符。

11.7.3 浮点数解决方案
1. bc 的基本用法

bash 计算器实际上是一种编程语言,允许在命令行中输入浮点数表达式,然后解释并计算该
表达式,最后返回结果。

在shell 提示符下通过bc 命令访问bash 计算器,要退出bash 计算器,必须输入quit。

  1. $ bc
  2. bc 1.06.95
  3. Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
  4. This is free software with ABSOLUTELY NO WARRANTY.
  5. For details type 'warranty'.
  6. 12 * 5.4
  7. 64.8
  8. 3.156 * (3 + 5)
  9. 25.248
  10. quit
  11. $
2. 在脚本中使用bc

可以用命令替换来运行bc 命令,将输出赋给变量,基本格式如下

variable=$(echo "options; expression" | bc)

  1. $ cat test11
  2. #!/bin/bash
  3. var1=20
  4. var2=3.14159
  5. var3=$(echo "scale=4; $var1 * $var1" | bc)
  6. var4=$(echo "scale=4; $var3 * $var2" | bc)
  7. echo The final result is $var4
  8. $

涉及更多的数字。如果要进行大量运算,那么在一个命令行中列出多个表达式容易让人犯晕。最好的办法是使用内联输入重定向,它允许直接在命令行中重定向数据,字符串 EOF 标识了内联重定向数据的起止基本格式如下:

variable=$(bc << EOF
options
statements
expressions
EOF
)

  1. $ cat test12
  2. #!/bin/bash
  3. var1=10.46
  4. var2=43.67
  5. var3=33.2
  6. var4=71
  7. var5=$(bc << EOF
  8. scale = 4
  9. a1 = ( $var1 * $var2)
  10. b1 = ($var3 * $var4)
  11. a1 + b1
  12. EOF
  13. )
  14. echo The final answer for this mess is $var5
  15. $

11.8 退出脚本

11.8.1查看退出状态码:echo $?

shell 中运行的每个命令都使用退出状态码来告诉shell 自己已经运行完毕。退出状态码是一
个0~255 的整数值,在命令结束运行时由其传给shell。你可以获取这个值并在脚本中使用。

Linux 提供了专门的变量$?来保存最后一个已执行命令的退出状态码。对于需要进行检查的
命令,必须在其运行完毕后立刻查看或使用$?变量。

  1. #执行date命令,对于成功结束的命令,其退出状态码是0。
  2. $ date
  3. Mon Jun 01 16:01:30 EDT 2020
  4. $ echo $?
  5. 0
  6. $

无效命令会返回退出状态码127。

11.8.2 自定义脚本的退出状态码exit命令

在默认情况下,shell 脚本会以脚本中的最后一个命令的退出状态码退出

可以改变这种默认行为,返回自己的退出状态码。exit 命令允许在脚本结束时指定一个退出状态码:1. 自定义参数或者2. 变量的数值,但是使用这个功能时要小心,因为退出状态码最大只能是255。

  1. # exit 命令允许在脚本结束时指定自定义参数作为退出状态码
  2. $ cat test13
  3. #!/bin/bash
  4. # testing the exit status
  5. var1=10
  6. var2=30
  7. var3=$[ $var1 + $var2 ]
  8. echo The answer is $var3
  9. exit 5
  10. $
  11. 当你检查脚本的退出状态码时,就会看到传给exit 命令的参数值:
  12. $ chmod u+x test13
  13. $ ./test13
  14. The answer is 40
  15. $ echo $?
  16. 5
  17. $
  18. # exit 命令允许在脚本结束时指定变量作为退出状态码
  19. $ cat test14b
  20. #!/bin/bash
  21. # testing the exit status
  22. var1=10
  23. var2=30
  24. var3=$[ $var1 * $var2 ]
  25. echo The value is $var3
  26. exit $var3
  27. $
  28. 现在运行它会得到如下输出:
  29. $ ./test14b
  30. The value is 300
  31. $ echo $?
  32. 44
  33. $

第12章结构化命令

12.1 使用if-then语句

bash shell 的if 语句会运行if 之后的命令。如果该命令的退出状态码为0(命令成功运行),那么位于then 部分的命令就会被执行。如果该命令的退出状态码是其他值,则then 部分的命令不会被执行,bash shell 会接着处理脚本中的下一条命令。fi 语句用来表示if-then 语句到此结束。if-then 语句的格式如下:
if command
then
commands
fi

12.2 if-then-else语句

当if 语句中的命令返回退出状态码0 时,then 部分中的命令会被执行,这跟普通的if-then
语句一样。当if 语句中的命令返回非0 退出状态码时,bash shell 会执行else 部分中的命令。if-then-else 语句在语句中提供了另外一组命令:
if command
then
commands
else
commands
fi

12.3 嵌套if语句

12.4 test命令

test 命令可以在if-then 语句中测试不同的条件。如果test 命令中列出的条件成立,那么
test 命令就会退出并返回退出状态码0。。如果条件不成立,那么test 命令就会退出并返回非0 的退出状态码,这使得if-then 语句不会再被执行。

12.4.1数值比较

  1. $ cat numeric_test.sh
  2. #!/bin/bash
  3. # Using numeric test evaluations
  4. #
  5. value1=10
  6. value2=11
  7. #
  8. if [ $value1 -gt 5 ]
  9. then
  10. echo "The test value $value1 is greater than 5."
  11. fi
  12. #
  13. if [ $value1 -eq $value2 ]
  14. then
  15. echo "The values are equal."
  16. else
  17. echo "The values are different."
  18. fi
  19. $

12.4.2 字符串比较

书写例子:

#
string1=soccer
string2=zorbfootball
#
if [ $string1 \> $string2 ]

if [ $string1 > $string2 ]

12.4.3 文件比较

1. 检查目录

-d 测试会检查指定的目录是否存在于系统中

  1. #
  2. jump_directory=/home/Torfa
  3. #
  4. if [ -d $jump_directory ]
  5. ...
2. 检查对象是否存在

-e 测试允许在使用文件或目录前先检查其是否存在

  1. $ cat update_file.sh
  2. #!/bin/bash
  3. # Check if either a directory or file exists
  4. #
  5. location=$HOME
  6. file_name="sentinel"
  7. #
  8. if [ -d $location ]
  9. then
3. 检查文件

-e 测试可用于文件和目录。

  1. #!/bin/bash
  2. # Check if object exists and is a directory or a file
  3. #
  4. object_name=$HOME
  5. #
  6. if [ -e $object_name ]
  7. then

12.5 复合条件测试

if-then 语句允许使用布尔逻辑将测试条件组合起来。可以使用以下两种布尔运算符。

        [ condition1 ] && [ condition2 ]
        [ condition1 ] || [ condition2 ]

第一种布尔运算使用布尔运算符AND 来组合两个条件。要执行then 部分的命令,两个条件
都必须满足。

第二种布尔运算使用OR 布尔运算符来组合两个条件。如果任意条件为真,那么then 部分
的命令就会执行。

12.6 if-then的高级特性

12.6.1使用单括号:创建一个子shell

单括号形式的test 命令格式如下:
(command)
在bash shell 执行command 之前,会先创建一个子shell,然后在其中执行命令。如果命令成
功结束,则退出状态码(参见第11 章)会被设为0,then 部分的命令就会被执行。如果命令的
退出状态码不为0,则不执行then 部分的命令。

警告:当你在if test 语句中使用进程列表(参见第5 章)时,可能会出现意料之外的结果。
哪怕进程列表中除最后一个命令之外的其他命令全都失败,子shell 仍会将退出状态码设
为0,then 部分的命令将得以执行。

12.6.2 使用双括号

双括号命令允许在比较过程中使用高级数学表达式

注意,双括号中表达式的大于号不用转义。这是双括号命令又一个优越性的体现。

例子:if (( $val1 ** 2 > 90 ))

12.6.3 使用双方括号

双方括号命令提供了针对字符串比较的高级特性

在进行模式匹配时,可以定义通配符或正则表达式(参见第20 章)来匹配字符串:

例子: if [[ $BASH_VERSION == 5.* ]]

12.7 case命令

case 命令会将指定变量与不同模式进行比较。如果变量与模式匹配,那么shell 就会执行为
该模式指定的命令。你可以通过竖线运算符在一行中分隔出多个模式。星号会捕获所有与已知模
式不匹配的值。有了case 命令,就无须再写大量的elif 语句来检查同一个变量的值了。case 命令会采用列表格式来检查变量的多个值,case格式如下:

case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac

  1. $ cat ShortCase.sh
  2. #!/bin/bash
  3. # Using a short case statement
  4. #
  5. case $USER in
  6. rich | christine)
  7. echo "Welcome $USER"
  8. echo "Please enjoy your visit.";;
  9. barbara | tim)
  10. echo "Hi there, $USER"
  11. echo "We're glad you could join us.";;
  12. testing)
  13. echo "Please log out when done with test.";;
  14. *)
  15. echo "Sorry, you are not allowed here."
  16. esac
  17. $

第13章 更多的结构化命令

13.1 for命令

提供了for 命令,以允许创建遍历一系列值的循环。每次迭代都使用其中一个值来执行已定义好的一组命令。for 命令的基本格式如下:
for var in list
do
commands
done

13.1.1读取列表中的值
  1. $ cat test1b
  2. #!/bin/bash
  3. # testing the for variable after the looping
  4. for test in Alabama Alaska Arizona Arkansas California Colorado
  5. do
  6. echo "The next state is $test"
  7. done
  8. echo "The last state we visited was $test"
  9. test=Connecticut
  10. echo "Wait, now we're visiting $test"
  11. $ ./test1b
  12. The next state is Alabama
  13. The next state is Alaska
  14. The next state is Arizona
  15. The next state is Arkansas
  16. The next state is California
  17. The next state is Colorado
  18. The last state we visited was Colorado
  19. Wa

13.1.2 读取列表中的复杂值 #
13.1.3 从变量中读取值列表 #
13.1.4 从命令中读取值列表 #
13.1.5 更改字段分隔符 #
13.1.6 使用通配符读取目录

最后,还可以用for 命令来自动遍历目录中的文件。为此,必须在文件名或路径名中使用
通配符,这会强制shell 使用文件名通配符匹配(file globbing)。文件名通配符匹配是生成与指定
通配符匹配的文件名或路径名的过程。

  1. $ cat test6
  2. #!/bin/bash
  3. # iterate through all the files in a directory
  4. for file in /home/rich/test/*
  5. do
  6. if [ -d "$file" ]
  7. then
  8. echo "$file is a directory"
  9. elif [ -f "$file" ]
  10. then
  11. echo "$file is a file"
  12. fi
  13. done
  14. $ ./test6
  15. /home/rich/test/dir1 is a directory
  16. /home/rich/test/myprog.c is a file
  17. /home/rich/test/myprog is a file
  18. /home/rich/test/myscript is a file
  19. /home/rich/test/newdir is a directory
  20. /home/rich/test/newfile is a file
  21. /home/rich/test/newfile2 is a file
  22. /home/rich/test/testdir is a directory
  23. /home/rich/test/testing is a file
  24. /home/rich/test/testprog is a file
  25. /home/rich/test/testprog.c is a file
  26. $

13.2 C语言风格的for命令

13.2.1 C语言中的for命令

迭代条件使用标准的数学符号定义。例如,考虑下面的
C 语言代码:
for (i = 0; i < 10; i++)
{
printf("The next number is %d\n", i);
}

  1. $ cat test8
  2. #!/bin/bash
  3. # testing the C-style for loop
  4. for (( i=1; i <= 10; i++ ))
  5. do
  6. echo "The next number is $i"
  7. done
  8. $ ./test8
  9. The next number is 1
  10. The next number is 2
  11. The next number is 3
  12. The next number is 4
  13. The next number is 5
  14. The next number is 6
  15. The next number is 7
  16. The next number is 8
  17. The next number is 9
  18. The next number is 10
  19. $
13.2.2使用多个变量

仿C 语言的for 命令也允许为迭代使用多个变量。循环会单独处理每个变量,你可以为每
个变量定义不同的迭代过程

  1. $ cat test9
  2. #!/bin/bash
  3. # multiple variables
  4. for (( a=1, b=10; a <= 10; a++, b-- ))
  5. do
  6. echo "$a - $b"
  7. done
  8. $ ./test9
  9. 1 - 10
  10. 2 - 9
  11. 3 - 8
  12. 4 - 7
  13. 5 - 6
  14. 6 - 5
  15. 7 - 4
  16. 8 - 3
  17. 9 - 2
  18. 10 - 1
  19. $

13.3 while命令

while 命令在某种程度上糅合了if-then 语句和for 循环。while 命令允许定义一个要
测试的命令,只要该命令返回的退出状态码为0,就循环执行一组命令
只要测试条件成立,while 命令就会不停地循环执行定义好的命令。必须在这些命令中修
改测试条件中用到的变量,否则就会陷入死循环。

13.3.1 while的基本格式

while 命令的格式如下:
while test command
do
other commands
done

  1. $ cat test10
  2. #!/bin/bash
  3. # while command test
  4. var1=10
  5. while [ $var1 -gt 0 ]
  6. do
  7. echo $var1
  8. var1=$[ $var1 - 1 ]
  9. done
  10. $ ./test10
  11. 10
  12. 9
  13. 8
  14. 7
  15. 6
  16. 5
  17. 4
  18. 3
  19. 2
  20. 1
  21. $
13.3.2 使用多个测试命令

在含有多个命令的while 语句中,在每次迭代时所有的测试命令都会被执行,包括最后一个测试命令失败的末次迭代。要小心这一点。另一处要留意的是该如何指定多个测试命令。
注意要把每个测试命令都单独放在一行中。

13.4 until命令

与while 命令工作的方式完全相反,until 命令要求指定一个返回非0 退出状态码的测试
命令。只要测试命令的退出状态码不为0,bash shell 就会执行循环中列出的命令。

until 命令的格式如下:
until test commands
do
other commands
done
与while 命令类似,你可以在until 命令语句中放入多个test command。最后一个命令
的退出状态码决定了bash shell 是否执行已定义的other commands。

  1. $ cat test12
  2. #!/bin/bash
  3. # using the until command
  4. var1=100
  5. until [ $var1 -eq 0 ]
  6. do
  7. echo $var1
  8. var1=$[ $var1 - 25 ]
  9. done
  10. $ ./test12
  11. 100
  12. 75
  13. 50
  14. 25
  15. $

13.5 嵌套循环

循环语句可以在循环内使用任意类型的命令,包括其他循环命令,这称为嵌套循环。注意,在使用嵌套循环时是在迭代中再进行迭代,命令运行的次数是乘积关系。不注意这点有可能会在

13.6 循环处理文件数据 #

13.7 循环控制

13.7.1 break命令
1. 跳出单个循环

格式

then
    break

2. 跳出内层循环

在处理多个循环时,break 命令会自动结束你所在的最内层循环

3. 跳出外层循环

有时你位于内层循环,但需要结束外层循环。break 命令接受单个命令行参数:
break n

其中n 指定了要跳出的循环层级。在默认情况下,n 为1,表明跳出的是当前循环。如果将n 设
为2,那么break 命令就会停止下一级的外层循环。

13.7.2 continue命令

continue 命令可以提前中止某次循环,但不会结束整个循环,格式:

then
continue

then
continue 2

13.8 处理循环的输出

在shell 脚本中,可以对循环的输出使用管道或进行重定向。这可以通过在done 命令之后
添加一个处理命令: > output.txt

  1. $ cat test23
  2. #!/bin/bash
  3. # redirecting the for output to a file
  4. for (( a = 1; a < 10; a++ ))
  5. do
  6. echo "The number is $a"
  7. done > test23.txt
  8. echo "The command is finished."

第14章 处理用户输入

14.1 传递参数

向shell 脚本传递数据的最基本方法是使用命令行参数

$ ./addem 10 30
本例向脚本addem 传递了两个命令行参数(10 和30)

14.1.1 读取参数

bash shell 会将所有的命令行参数都指派给称作位置参数(positional parameter)的特殊变量

在shell 脚本中,可以像使用其他变量一样使用$1 变量。shell 脚本会自动将命令行参数的值
分配给位置变量,无须做任何特殊处理。
如果需要输入更多的命令行参数,则参数之间必须用空格分开。shell 会将其分配给对应的位
置变量

  1. $ cat positional2.sh
  2. #!/bin/bash
  3. # Using two command-line parameters
  4. #
  5. product=$[ $1 * $2 ]
  6. echo The first parameter is $1.
  7. echo The second parameter is $2.
  8. echo The product value is $product.
  9. exit
  10. $
  11. $ ./positional2.sh 2 5
  12. The first parameter is 2.
  13. The second parameter is 5.
  14. The product value is 10.
  15. $
14.1.2 读取脚本名

使用位置变量$0 获取在命令行中运行的shell 脚本名。这在编写包含多种功能或生成日
志消息的工具时非常方便

14.2 特殊

  1. $ cat countparameters.sh
  2. #!/bin/bash
  3. # Counting command-line parameters
  4. #
  5. if [ $# -eq 1 ]
  6. then
  7. fragment="parameter was"
  8. else
  9. fragment="parameters were"
  10. fi
  11. echo $# $fragment supplied.
  12. exit
  13. $
  14. $ ./countparameters.sh
  15. 0 parameters were supplied.
  16. $
  17. $ ./countparameters.sh Hello
  18. 1 parameter was supplied.
  19. $

参数变量

14.2.1 参数统计

特殊变量$#含有脚本运行时携带的命令行参数的个数。你可以在脚本中的任何地方使用这
个特殊变量

14.2.2 获取所有的数据

$*变量和$@变量可以轻松访问所有参数,它们各自包含了所有的命令行参数。$*变量会将所有参数视为单个参数,而$@变量会单独处理每个参数

  1. $ cat grabdisplayallparams.sh
  2. #!/bin/bash
  3. # Exploring different methods for grabbing all the parameters
  4. #
  5. echo
  6. echo "Using the \$* method: $*"
  7. count=1
  8. for param in "$*"
  9. do
  10. echo "\$* Parameter #$count = $param"
  11. count=$[ $count + 1 ]
  12. done
  13. #
  14. echo
  15. echo "Using the \$@ method: $@"
  16. count=1
  17. for param in "$@"
  18. do
  19. echo "\$@ Parameter #$count = $param"
  20. count=$[ $count + 1 ]
  21. done
  22. echo
  23. exit
  24. $

14.3 移动参数 #

14.4 处理选项 # 

14.4.1 查找选项

14.4.2 使用getopt命令

14.4.3 使用getopts命令

14.5 选项标准化

14.6 获取用户输入

14.6.1 基本的读取 

read

  1. $ cat askname.sh
  2. #!/bin/bash
  3. # Using the read command
  4. #
  5. echo -n "Enter your name: "
  6. read name
  7. echo "Hello $name, welcome to my script."
  8. exit
  9. $
  10. $ ./askname.sh
  11. Enter your name: Richard Blum
  12. Hello Richard Blum, welcome to my script.
  13. $

14.6.2 超时 #

14.6.3 无显示读取 #

14.6.4 从文件中读取 # 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/185054
推荐阅读
相关标签
  

闽ICP备14008679号