## 命令执行顺序控制 * 通常情况下,一个脚本完成一个特定的任务,如:创建目录,然后在目录中创建日志文件。 或者将文件备份后删除原文件,否则可能会丢失文件。也就是在执行某个命令的时需要依赖前一个命令是否执行成功。 * 如果希望在成功地执行一个命令之后再执行另一个命令,或者在一个命令失败后再执行另一个命令,` &&和|| `可以完成这样的功能。相应的命令可以是系统命令或脚本。 * 另外,使用` ()和{ } `还可以在当前脚本中执行一组命令。 ### 一、使用&&执行命令序列 * 使用&&的一般形式为: 命令 1 && 命令 2 && 命令 3 * 解释: * 1>当命令 1 返回真后(返回 0,成功被执行),命令 2 才能够被执行,否则,&&后面的命令都不会执行。 * 2>当命令 2 返回真后才会执行命令 3,否则不会执行命令 3。就如 Java 中的**短路与**相同。 * 例子:使用&&执行多个命令序列 [root@localhost test]# mkdir dir1 && echo "创建目录成功" 创建目录成功 [root@localhost test]# mkdir dir1 && echo "创建目录成功" mkdir: 无法创建目录"dir1": 文件已存在 [root@localhost test]# cd /home/hadoop01 && mkdir logs && cd logs && touch log.log && pwd /home/hadoop01/logs 目录创建成功,后面的命令才会执行输出。第二个命令序列也是一样,前面的命令执行成功,后面的命令才会继续执行。 命令序列通常使用在 if 语句中,如果命令序列执行全部成功则执行分支中的语句。 如果全部执行成功退出码为 0,否则为非 0,if 语句根据退出码判断执行分支语句。 ### 二、使用||执行命令序列 * 使用||的一般形式为: 命令 1 || 命令 2 || 命令 3 * 解释: * 1>当命令 1 执行失败(返回非 0 的值),命令 2 才能够被执行,否则,||后面的命令都不会执行。 * 2>当命令 2 执行也失败了才会执行命令 3,否则不会执行命令 3。就如 Java 中的**短路或**相同。 * 例子:使用||执行多个命令序列 #!/bin/bash # 错误信息不输出 exec 2>/dev/null cp file1 file2 || echo "文件拷贝失败" * 例子:如果目录存在,移动到临时目录,然后继续创建 mkdir dir1 || mv dir1 /tmp/dir1 && mkdir dir1 * 例子:命令也可以是脚本,首先创建一个脚本。 #!/bin/bash # 脚本中的错误信息忽略 exec 2>/dev/null # 切换到目录 cd /home/hadoop01 # 拷贝不存在的文件 cp file1 file2 * 执行脚本: [root@localhost test]# t.sh || "文件拷贝失败" -bash: 文件拷贝失败: command not found ### 三、使用()和{}执行命令序列 * 如果想执行一组命令,可以采用两种方式,将命令组放在` () `或` {} `中,**如果在一行需要使用命令分隔符; 将命令分开,如果不在一行,就不需要了**。 * **这两种方式的区别是,()可以在命令行上使用,而{}方式只能在脚本中使用**。另外,()方式执行脚本不会改变当前命令行状态。 * 例子:在命令行执行()语句块 [root@localhost test]# (cd /home/hadoop01;pwd) /home/hadoop01 [root@localhost test]# * **另外,这两种方式的区别是,()方式可以引用父脚本中的变量,但不能改变变量的值,而{}方式可以引用父脚本中的变量,也可以改变变量的值**。 * 例子:两种方式引用父进程中的局部变量,并修改变量的值,比较两种方式的区别。 * 需要注意的是,这两种方式不会启动一个新的子进程,在子进程中执行命令,而是都在父进程中执行。 * 例子:在脚本中使用两种方式执行,验证是否创建了新的子进程。 * 另外,在()内声明的变量,在脚本中无法访问,相当于局部变量,而在{}内声明的变量在脚本中可以访问 * 例子:在()中声明的变量类似局部变量,脚本中不能访问。在{}中声明的变量,脚本中可以访问。 * 这两种方式通常使用的场景是重定向输入和重定向输出,从一个文件中读取或重定向输出到文件。 * 例子:使用两种方式重定向输入和重定向输出到文件。 * 将代码块{…}中的所有标准输出内容都重新定向到文件中,注意,只有标准输出到控制台的内容才会写入到文件中。 * 例:代码块的用法。 #!/bin/bash # {}>file FILE_DIR=/home/hadoop01/bash01/dir1 # 代码块 { # 判断变量是否是目录 if [ -d "$FILE_DIR" ] then # 标准输出到控制台的信息,所以会写到文件中 echo "Add content to the '$FILE_DIR/hadoop013.txt'" # 标准输出已经重定向到文件中了,所以不会显示到控制台,也不会写到文件中 echo "Bash Sheel!" >> "$FILE_DIR"/hadoop013.txt # 同上 echo "Linux!" >> "$FILE_DIR"/hadoop013.txt fi # 重新定向到文件中,可以作为日志 } > "$FILE_DIR"/bashbak1 # 显示文件内容:Add content to the '/home/hadoop01/bash01/dir1/hadoop013.txt' cat "$FILE_DIR"/bashbak1 * 从文件中输出内容。 * 例:read 命令的用法例子。 #!/bin/bash # < FILE_DIR=/home/hadoop01/hadoop01/dir1/hadoop012.txt # 从文件中读取第一行到变量 line1 read line1 < "$FILE_DIR" # 还是读取第一行 read line2 < "$FILE_DIR" # 两个变量的内容都是文件的第一行内容:Hello YARN! echo "$line1" echo "$line2" # 代码块{…}中读取两次到两个变量,变量 line3 读取的是第一行 # 变量 line4 读取的是文件的第二行 { read line3 read line4 } < "$FILE_DIR" echo # 输出:Hello hadoop01! echo "$line3" # 输出:Hello MapReduce! echo "$line4"