判断条件参数详情

File Operators Details
-e "$file" 如果文件存在,则返回 true。
-d "$file" 如果文件存在且是目录,则返回 true
-f "$file" 如果文件存在且是常规文件,则返回 true
-h "$file" 如果文件存在且是符号链接,则返回 true
String Comparators Details
-z "$str" 如果字符串长度为零,则为 True
-n "$str" 如果字符串长度不为零,则为 True
"$str" = "$str2" 如果字符串 $str 等于字符串 $str2,则为 True。对于整数型数据来说不是最佳选择。可能有效,但不一致
"$str" != "$str2" 如果字符串不相等,则为 True
Integer Comparators Details
"$int1" -eq "$int2" 如果整数相等,则为 True
"$int1" -ne "$int2" 如果整数不相等,则为 True
"$int1" -gt "$int2" 如果 int1 大于 int2,则为 True
"$int1" -ge "$int2" 如果 int1 大于或等于 int2,则为 True
"$int1" -lt "$int2" 如果 int1 小于 int2,则为 True
"$int1" -le "$int2" 如果 int1 小于或等于 int2,则为 True

Section 10.1: 有条件地执行命令列表

如何有条件地执行命令列表

任何内置命令、表达式或函数,以及任何外部命令或脚本,都可以使用 && (and) 和 || (or) 操作符有条件地执行。

例如,只有当 cd 命令被执行成功后才打印当前目录。

cd my_directory && pwd

同样,如果 cd 命令失败它也会退出,从而避免灾难的发生:

cd my_directory || exit
rm -rf *

在以这种方式组合多个语句时,重要的是要记住(与许多 C 风格语言不同)这些运算符没有优先级,并且是左关联的。

因此,这条语句将按照预期的方式运行...

cd my_directory && pwd || echo "No such directory"
  • 如果 cd 成功,则执行 && pwd,并打印出当前工作目录名。除非 pwd 失败(很少见),否则不会执行 || echo ...。
  • 如果 cd 失败,&& pwd 将被跳过,|| echo ... 将会运行。

但下面这个命令不会(如果你在想 “if...then...else”)...

cd my_directory && ls || echo "No such directory"
  • 如果 cd 失败,则跳过 && ls,执行 || echo ...。
  • 如果 cd 成功,则执行 && ls。
  • 如果 ls 成功,|| echo ... 将被忽略。(目前情况良好)
  • 但是 ...... 如果 ls 失败,|| echo ... 也会被执行。

前一个命令是 ls,而不是 cd。

为什么要在命令列表中使用条件执行

条件执行比 if...then 要快一些,但它的主要优点是允许函数和脚本提前退出,或者说 “短路”。

与许多语言(如 C 语言)不同的是,在 C 语言中,内存是明确分配给结构体和变量等的(因此必须先进行分配),而 bash 则在暗处进行处理。在大多数情况下,我们不需要在离开函数之前清理任何东西。返回语句将取消分配函数本地的所有内容,并在堆栈上的返回地址重新开始执行。

因此,尽快从函数中返回或退出脚本可以避免不必要的代码执行,从而大大提高性能并减少系统负载。例如...

my_function () {

    ### ALWAYS CHECK THE RETURN CODE

    # one argument required. "" evaluates to false(1)
    [[ "$1" ]] || return 1

    # work with the argument. exit on failure
    do_something_with "$1" || return 1
    do_something_else || return 1

    # Success! no failures detected, or we wouldn't be here
    return 0
}

Section 10.2: If 声明

if [[ $1 -eq 1 ]]; then
        echo "1 was passed in the first parameter"
elif [[ $1 -gt 2 ]]; then
        echo "2 was not passed in the first parameter"
else
        echo "The first parameter was not 1 and is not more than 2."
fi

结尾的 fi 是必要的,但 elif 和(或) else 子句可以省略。

then 前面的分号 ; 是将两条命令合并到一行的标准语法;只有将 then 移到下一行时才可以省略。

需要注意的是,括号 [[ 不是语法的一部分,但被视为一条命令;是这条测试命令的退出代码。因此,必须始终在括号内加入空格。

这也意味着可以测试任何命令的结果。如果命令的退出代码为 0,则认为语句为真。

if grep "foo" bar.txt; then
        echo "foo was found"
else
        echo "foo was not found"
fi

数学表达式放在双括号内时,也会以同样的方式返回 0 或 1,并且也可以进行测试:

if (( $1 + 5 > 91 )); then
        echo "$1 is greater than 86"
fi

你可能还会遇到带单括号的 if 语句。这些语句是在 POSIX 标准中定义的,保证可以在包括 Bash 在内的所有兼容 POSIX 的 shell 中运行。其语法与 Bash 中的非常相似:

if [ "$1" -eq 1 ]; then
        echo "1 was passed in the first parameter"
elif [ "$1" -gt 2 ]; then
        echo "2 was not passed in the first parameter"
else
        echo "The first parameter was not 1 and is not more than 2."
fi

Section 10.3: 在数组上循环

for 循环:

arr=(a b c d e f)
for i in "${arr[@]}";do
        echo "$i"
done

Or

for ((i=0;i<${#arr[@]};i++));do
        echo "${arr[$i]}"
done

while 循环:

i=0
while [ $i -lt ${#arr[@]} ];do
        echo "${arr[$i]}"
        i=$(expr $i + 1)
done

Or

i=0
while (( $i < ${#arr[@]} ));do
  echo "${arr[$i]}"
  ((i++))
done

Section 10.4: 使用 For 循环对数字进行列表迭代

#! /bin/bash
for i in {1..10}; do # {1..10} expands to "1 2 3 4 5 6 7 8 9 10"
        echo $i
done

输出结果如下:

1
2
3
4
5
6
7
8
9
10

Section 10.5: continue 和 break

continue 的示例:

for i in [series]
do
    command 1
    command 2
    if (condition) # Condition to jump over command 3
            continue # skip to the next value in "series"
    fi
    command 3
done

break 的示例:

for i in [series]
do
    command 4
    if (condition) # Condition to break the loop
    then
        command 5 # Command if the loop needs to be broken
        break
    fi
    command 6 # Command to run if the "condition" is never true
done

Section 10.6: 循环中断

中断多重循环:

arr=(a b c d e f)
for i in "${arr[@]}";do
    echo "$i"
    for j in "${arr[@]}";do
        echo "$j"
        break 2
    done
done

输出:

a
a

中断单个循环:

arr=(a b c d e f)
for i in "${arr[@]}";do
    echo "$i"
    for j in "${arr[@]}";do
        echo "$j"
        break
    done
done

输出:

a
a
b
a
c
a
d
a
e
a
f
a

Section 10.7: While 循环

#! /bin/bash
i=0
while [ $i -lt 5 ] #While i is less than 5
do
    echo "i is currently $i"
    i=$[$i+1] #Not the lack of spaces around the brackets. This makes it a not a test expression
done #ends the loop

Watch that there are spaces around the brackets during the test (after the while statement). These spaces are necessary.

注意在判断过程中(while 语句之后),括号周围有空格。这些空格是必要的。

This loop outputs:

该循环输出:

i is currently 0
i is currently 1
i is currently 2
i is currently 3
i is currently 4

Section 10.8: 使用 C 风格语法的 For 循环

C 风格 for 循环的基本格式是:

for (( variable assignment; condition; iteration process ))

注意

  • 在 C 风格 for 循环中对变量的赋值可以包含空格,这与通常的赋值不同

  • C 风格 for 循环中的变量不在前面加上 $。

示例

for (( i = 0; i < 10; i++ ))
do
        echo "The iteration number is $i"
done

此外,我们还可以在 C 风格 for 循环中处理多个变量:

for (( i = 0, j = 0; i < 10; i++, j = i * i ))
do
        echo "The square of $i is equal to $j"
done

Section 10.9: Until 循环

Until 循环会一直执行到条件为 true

i=5
until [[ i -eq 10 ]]; do #Checks if i=10
    echo "i=$i" #Print the value of i
    i=$((i+1)) #Increment i by 1
done

Output:

i=5
i=6
i=7
i=8
i=9

当 i 达到 10 时,until 循环中的条件变为 true,循环结束。

Section 10.10: 带 case 的 Switch 语句

使用 case 语句,您可以将数值与一个变量匹配。

传递给 case 的参数会被展开,并尝试与每个模式匹配。

如果发现匹配,则执行 ;; 之前的命令。

case "$BASH_VERSION" in
    [34]*)
            echo {1..4}
            ;;
    *)
            seq -s" " 1 4
esac

模式不是正则表达式,而是 shell 模式匹配(又称 globs)。

Section 10.11: 不带单词列表参数的 For 循环

for arg; do
        echo arg=$arg
done

没有单词列表参数的 for 循环将遍历位置参数。换句话说,上述示例等同于以下代码:

for arg in "$@"; do
        echo arg=$arg
done

In other words, if you catch yourself writing for i in "$@"; do ...; done, just drop the in part, and write simply for i; do ...; done.

换句话说,如果你发现自己在写 for i in ”$@“; do ...; done,就去掉 in部分,直接写 for i; do ...; done。