Shell脚本:条件执行
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
这是Shell脚本系列教程的第二部分。如果您错过了第一部分,可以在这里找到。
另外请注意,大部分代码仅使用bash和zshshell 进行过测试,可能无法在其他 shell 上运行。
条件执行意味着您可以选择仅在满足特定条件时才执行代码。如果没有这种能力,您只能依次执行一条又一条命令。能够测试系统状态和进程环境变量的各种信息,意味着 shell 脚本可以执行远比以往更强大的操作。在本文中,我们将探讨test operators条件if/then/else语句case。
test又名[
通过测试,我们可以检查例如:文件是否存在、一个数字是否大于另一个数字、比较字符串是否相等……
句法:
[ condition-to-test-for ]
例子:
[ -e /etc/passwd ]
如上文所述,`is` 的另一个名称是test`is` [。它也是一个 shell 内置函数(这意味着即使你的 Unix 环境配置不同, shell 本身也会将其解释[为`is`)。调用 `is` 时,它的参数需要一个 ` is` 关键字,除此之外,它的功能与 `is` 相同。test[]
test -e /etc/passwd
# as above so below
[ -e /etc/passwd ]
该命令会检查是否etc/passwd存在,如果存在,则返回true命令退出状态0。如果不存在,则命令以退出状态退出1(有关退出状态的更多信息,请参见下一篇文章)。
注意[:运算符和符号之间的空格]是必需的!例如:` [-e /etc/passwd ]\n` 是行不通的;它会被解释为test-e /etc/passwd ]`\n`,这会报错,因为]`\n` 没有开头[。` [\n` 实际上是一个程序,就像 `\n`ls和其他程序一样,它必须被空格包围。
所以,记住:所有运算符周围都要加上空格。
注意:您可以使用以下命令撤销测试结果!:
if [ ! -r “$1” ]; then echo "File $1 is not readable – skipping."; fi
如您所见,test这是一个简单但功能强大的比较工具。要了解完整详情,请man test在您的系统上运行,但以下是一些用法和典型示例:
文件测试运算符:
-d FILE #True if the file is a directory
-e FILE #True if the file exists
-f FILE #True if the file exists and it's regular file
-r FILE #True if the file is readable by you
-s FILE #True if the file exists and it's not empty
-w FILE #True if the file is writable by you
-x FILE #True if the file is executable by you
字符串测试运算符:
-z STRING #True if the string is empty
-n STRING #True if the string is not empty
STRING1 = STRING2 #True if the strings are equal
STRING1 != STRING2 #True if the strings are not equal
算术测试:
arg1 -eq arg2 #True if the arguments are equal
arg1 -ne arg2 #True if the arguments are not equal
arg1 -lt arg2 #True if the arg1 is less than arg2
arg1 -le arg2 #True if arg1 is less than or equal to arg2
arg1 -gt arg2 #True if arg1 is greater than arg2
arg1 -ge arg2 #True if arg1 is greater than or equal to arg2
&&和||
可以使用“&&与||”运算符组合测试和/或链接多个命令。它们分别执行逻辑与和逻辑或运算。
-
&& = ANDmkdir /tmp/bak && cp test.txt /tmp/bak&&只有当上一个命令成功执行(即以退出状态退出)时,才会执行下一个命令0。 -
|| = ORcp test.txt /tmp/bak || cp test.txt /tmp该
||运算符执行逻辑或运算,因此,当只需要满足其中一个条件,而不需要满足哪个条件时,就可以使用此功能。
#! /bin/bash
HOST="google.com"
ping -c 1 $HOST && echo "$HOST reachable."
如果/那么
几乎所有编程语言都有 if/then/else 结构,Shell 也不例外。其语法使用方括号进行判断,并且必须包含thenandfi语句,其作用类似于 C 和其他一些语言中的花括号 { 和 }。
句法:
if [ condition ]
then
statements for when the condition is true
fi
除了逗号后的换行符之外,所有这些换行符都是必需的,或者可以用分号代替。再次提醒:逗号和符号then周围的空格也是必需的,所以最好将其简化为(请不要这样做):[]if [ condition ];then statements;fi
使用分号将 then 和 if 放在同一行是很常见的做法。
例子:
MY_SHELL="zsh"
if [ "$MY_SHELL" = "zsh" ]
then
echo "You are the zsh shell user!"
fi
别的
您可能希望尽可能运行该命令,但如果无法运行,则继续执行脚本。一种(更简单也最常用的)方法是使用 ELSE 语句:
if [ condition ]; then
statements for when the condition is true
else
statements for when the condition is false
fi
#!/bin/bash
# Check for likely causes of failure
if [ -r "$1" ]; then
cat "$1"
else
echo "Error: $1 is not a readable file."
fi
这段代码尝试读取cat作为第一个参数传递给它的文件("$1"用双引号将其括起来,以允许文件名包含空格),如果读取失败,则会输出错误消息。
ELIF
elifelse`else if` 是一种允许你在语句中添加条件的结构if。它是 `else if` 的缩写,这样就可以更简洁地编写一长串可能的操作。这使得代码更易于编写、更易于阅读,最重要的是,更易于调试。
#!/bin/bash
OS=`uname -s`
if [ "$OS" = "FreeBSD" ]; then
echo "This Is FreeBSD"
elif [ "$OS" = "CYGWIN_NT-5.1" ]; then
echo "This is Cygwin"
elif [ "$OS" = "SunOS" ]; then
echo "This is Solaris"
elif [ "$OS" = "Darwin" ]; then
echo "This is Mac OSX"
elif [ "$OS" = "Linux" ]; then
echo "This is Linux"
else
echo "Failed to identify this OS"
fi
这比它可能变成的那种嵌套代码地狱要易读得多。else
case陈述
case与传统的语句结构相比,`case` 语句提供了一种更简洁、更易写、更易读的替代方案if/then/else,尤其是在需要测试大量可能值的情况下。使用 `case` 语句,您可以列出要识别和处理的值,然后为每个值提供一段代码块。`case`
语句的一个常见应用场景是系统启动脚本。
语法:
case "$VAR" in
pattern_1)
# Some commands here.
;; # Execution will stop when the double semicolon is reached
pattern_n)
# Some commands here.
;;
esac
例子:
#!/bin/bash
OS=`uname -s`
case "$OS" in
FreeBSD) echo "This is FreeBSD" ;;
CYGWIN_NT-5.1) echo "This is Cygwin" ;;
SunOS) echo "This is Solaris" ;;
Darwin) echo "This is Mac OSX" ;;
Linux) echo "This is Linux" ;;
*) echo "Failed to identify this OS" ;;
esac
虽然它看起来像是一个特殊指令,但*实际上它只是最通用的通配符,因为它能匹配任何字符串。这也意味着我们可以进行更高级的模式匹配RegEx,例如 `\n`。
请注意,图案区分大小写。
Bash 实现中一个不太为人所知的特性是,你可以用 `\n`或 ` \n`case结束语句,而不仅仅是 `\n`。` \n`表示不会执行任何其他语句,但如果你用 `\n` 结束语句,所有后续的 `\n` 语句仍然会被执行。如果你用 `\n` 结束语句,则该 `\n` 语句将被视为已匹配到 `\n` 语句。;;&;&;;;;;;&;&
#!/bin/bash
read -p "Give me a word: " input
echo -en "That's "
case $input in
*[[:digit:]]*) echo -en "numerical " ;;&
*[[:lower:]]*) echo -en "lowercase " ;;&
*[[:upper:]]*) echo -en "uppercase " ;;&
*) echo "input." ;;
esac
$ ./case1.sh
Give me a word: Hello 123
That's numerical lowercase uppercase input.
此功能仅适用于 bash shell;它并非 Bourne shell 的标准功能,因此如果您需要编写可移植的脚本,请不要指望它能正常工作。在其他 shell 中,它会引发语法错误。
本文介绍了控制条件执行的各种方法——从简单的条件语句if/then/else construct,到可以使用条件语句执行的不同操作test,再到更灵活的case语句,用于匹配不同的输入集。
我必须承认,一开始我觉得写关于 shell 编程的文章最多也就两三篇,但实际上内容非常丰富,即使是这篇文章和之前的文章,也只涵盖了我所写主题的一半。如果你想更深入地学习 shell 编程,我强烈推荐《高级 Bash 脚本指南》和《经典 Shell 脚本》。下一篇文章我会简单介绍一下位置参数、退出码以及(希望)函数。感谢阅读!
文章来源:https://dev.to/puritanic/shellscripting-conditional-execution-3kgm
