> ## Content Index
> Fetch the complete content index at: https://yonglun.me/llms.txt
> Use this file to discover other available public pages before exploring further.

# pure bash bible 中文版
- URL: https://yonglun.me/bash-bible/
- Published: 2019-12-17T12:31:47.000Z
- Updated: 2025-04-22T09:55:00.000Z
- Author: Yonglun
- Tags: Open Source, Linux, Bash, #lang-zh

# 译者前言

[pure bash bible](https://github.com/dylanaraps/pure-bash-bible?ref=yonglun.me) 是Dylan Araps 在github 上发布的一本关于Linux bash 的电子书，实用性强。在此将其翻译为中文，既加深自己的理解，也为需要的朋友提供参考和帮助。翻译有错漏的地方，请各位予以指正，感谢！

# 前言

本书包含了一系列纯bash脚本实现的程序，用于替代相同功能的外部程序。bash 脚本语言功能强大，可以在不依赖外部程序的条件下，完成我们工作中的大部分的需求。

在bash 中调用外部程序是比较消耗资源的，会对脚本应用的执行效率带来明显的影响。使用纯bash脚本编写应用执行效率高，外部依赖少，还能帮助我们更好理解bash语言原生的功能。

本书的内容可以作为编写bash脚本应用中遇到问题提供参考。通过函数形式的样例代码演示了如何将这些解决方案应用到代码中。

# 1.字符串操作

## 1.1 移除字符串开头和结尾的空格

这是对sed, awk, perl及其它工具的一个替代。下面的函数找出字符串开头及结尾的空格，将它们从字符串中移除。bash内置的:用于代替临时变量。

### 函数示例

```bash
trim_string() {
    # Usage: trim_string "   example   string    "
    : "${1#"${1%%[![:space:]]*}"}"
    : "${_%"${_##*[![:space:]]}"}"
    printf '%s\n' "$_"
}

```

### 使用示例

```bash
$ trim_string "    Hello,  World    "
Hello,  World
$ name="   John Black  "
$ trim_string "$name"
John Black

```

## 1.2 移除字符串中的多余的空格

这是对sed, awk, perl及其它工具的一个替代。下面的函数移除字符串中多余的空格，保留单词之间的间隔。

### 函数示例

```bash
# shellcheck disable=SC2086,SC2048
trim_all() {
    # Usage: trim_all "   example   string    "
    set -f
    set -- $*
    printf '%s\n' "$*"
    set +f
}

```

### 使用示例

```bash
$ trim_all "    Hello,    World    "
Hello, World

$ name="   John   Black  is     my    name.    "
$ trim_all "$name"
John Black is my name.

```

## 1.3 对字符串进行匹配正则表达式匹配

bash 的正则表达式匹配功能可以在大部分的应用场景中替代sed工具。

> 注意：这是bash平台相关的功能之一。bash会使用系统中安装的正则表达式引擎来处理。如果需要保持兼容性，请指明使用POSIX POSIX regex 功能。

> 注意：该示例只返回首个matching group。当有多个matching group时，需要对示例进行修订。

### 函数示例

```bash
regex() {
    # Usage: regex "string" "regex"
    [[ $1 =~ $2 ]] && printf '%s\n' "${BASH_REMATCH[1]}"
}

```

### 使用示例

```bash
$ # Trim leading white-space.
$ regex '    hello' '^\s*(.*)'
hello

$ # Validate a hex color.
$ regex "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
#FFFFFF

$ # Validate a hex color (invalid).
$ regex "red" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
# no output (invalid)

```

### 在脚本中的使用示例

```bash
is_hex_color() {
    if [[ $1 =~ ^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$ ]]; then
        printf '%s\n' "${BASH_REMATCH[1]}"
    else
        printf '%s\n' "error: $1 is an invalid color."
        return 1
    fi
}

read -r color
is_hex_color "$color" || color="#FFFFFF"

# Do stuff.

```

## 1.4 根据指定的分隔符分割字符串

> 注意：需要bash 4及以上版本

可以作为 cut, awk 及其它根据的替代品。

### 函数示例

```bash
split() {
   # Usage: split "string" "delimiter"
   IFS=$'\n' read -d "" -ra arr <<< "${1//$2/$'\n'}"
   printf '%s\n' "${arr[@]}"
}

```

### 使用示例

```bash
$ split "apples,oranges,pears,grapes" ","
apples
oranges
pears
grapes

$ split "1, 2, 3, 4, 5" ", "
1
2
3
4
5

# Multi char delimiters work too!
$ split "hello---world---my---name---is---john" "---"
hello
world
my
name
is
john

```

## 1.5 将字符串转换为小写

> 注意：需要bash 4及以上版本

### 函数示例

```bash
lower() {
    # Usage: lower "string"
    printf '%s\n' "${1,,}"
}

```

### 使用示例

```bash
$ lower "HELLO"
hello

$ lower "HeLlO"
hello

$ lower "hello"
hello

```

## 1.6 将字符串转换为大写

> 注意：需要bash 4及以上版本

### 函数示例

```bash
upper() {
    # Usage: upper "string"
    printf '%s\n' "${1^^}"
}

```

### 使用示例

```bash
$ upper "hello"
HELLO

$ upper "HeLlO"
HELLO

$ upper "HELLO"
HELLO

```

## 1.7 反转字符串的大小写

> 注意：需要bash 4及以上版本

#### 函数示例

```bash
reverse_case() {
    # Usage: reverse_case "string"
    printf '%s\n' "${1~~}"
}

```

### 使用示例

```bash
$ reverse_case "hello"
HELLO

$ reverse_case "HeLlO"
hElLo

$ reverse_case "HELLO"
hello

```

## 1.8 删除字符串中的引号

### 函数示例

```bash
trim_quotes() {
    # Usage: trim_quotes "string"
    : "${1//\'}"
    printf '%s\n' "${_//\"}"
}

```

### 使用示例

```bash
$ var="'Hello', \"World\""
$ trim_quotes "$var"
Hello, World

```

## 1.9 在字符串中移除所有满足匹配模式的实例

### 函数示例

```bash
strip_all() {
    # Usage: strip_all "string" "pattern"
    printf '%s\n' "${1//$2}"
}

```

### 使用示例

```bash
$ strip_all "The Quick Brown Fox" "[aeiou]"
Th Qck Brwn Fx

$ strip_all "The Quick Brown Fox" "[[:space:]]"
TheQuickBrownFox

$ strip_all "The Quick Brown Fox" "Quick "
The Brown Fox

```

## 1.10 在字符串中移除首项满足匹配模式的实例

### 函数示例

```bash
strip() {
    # Usage: strip "string" "pattern"
    printf '%s\n' "${1/$2}"
}

```

### 使用示例

```bash
$ strip "The Quick Brown Fox" "[aeiou]"
Th Quick Brown Fox

$ strip "The Quick Brown Fox" "[[:space:]]"
TheQuick Brown Fox

```

## 1.11 在字符串开头删除满足匹配模式的实例

### 函数示例

```bash
lstrip() {
    # Usage: lstrip "string" "pattern"
    printf '%s\n' "${1##$2}"
}

```

### 使用示例

```bash
$ lstrip "The Quick Brown Fox" "The "
Quick Brown Fox

```

## 1.12 在字符串结尾删除满足匹配模式的实例

### 函数示例

```bash
rstrip() {
    # Usage: rstrip "string" "pattern"
    printf '%s\n' "${1%%$2}"
}

```

### 使用示例

```bash
$ rstrip "The Quick Brown Fox" " Fox"
The Quick Brown

```

## 1.13 对字符串进行URL 编码

### 函数示例

```bash
urlencode() {
    # Usage: urlencode "string"
    local LC_ALL=C
    for (( i = 0; i < ${#1}; i++ )); do
        : "${1:i:1}"
        case "$_" in
            [a-zA-Z0-9.~_-])
                printf '%s' "$_"
            ;;

            *)
                printf '%%%02X' "'$_"
            ;;
        esac
    done
    printf '\n'
}

```

### 使用示例

```bash
$ urlencode "https://github.com/dylanaraps/pure-bash-bible"
https%3A%2F%2Fgithub.com%2Fdylanaraps%2Fpure-bash-bible

```

## 1.14 对字符串进行URL 解码

### 函数示例

```bash
urldecode() {
    # Usage: urldecode "string"
    : "${1//+/ }"
    printf '%b\n' "${_//%/\\x}"
}

```

### 使用示例

```bash
$ urldecode "https%3A%2F%2Fgithub.com%2Fdylanaraps%2Fpure-bash-bible"
https://github.com/dylanaraps/pure-bash-bible

```

## 1.15 检查字符串中是否包含另一个字符串

### 使用条件测试方式

```bash
if [[ $var == *sub_string* ]]; then
    printf '%s\n' "sub_string is in var."
fi

# Inverse (substring not in string).
if [[ $var != *sub_string* ]]; then
    printf '%s\n' "sub_string is not in var."
fi

# This works for arrays too!
if [[ ${arr[*]} == *sub_string* ]]; then
    printf '%s\n' "sub_string is in array."
fi

```

### case 方式

```bash
case "$var" in
    *sub_string*)
        # Do stuff
    ;;

    *sub_string2*)
        # Do more stuff
    ;;

    *)
        # Else
    ;;
esac

```

## 1.16 检查字符串中是否以另一个字符串开头

```bash
if [[ $var == sub_string* ]]; then
    printf '%s\n' "var starts with sub_string."
fi

# Inverse (var does not start with sub_string).
if [[ $var != sub_string* ]]; then
    printf '%s\n' "var does not start with sub_string."
fi

```

## 1.17 检查字符串中是否以另一个字符串结尾

```bash
if [[ $var == *sub_string ]]; then
    printf '%s\n' "var ends with sub_string."
fi

# Inverse (var does not end with sub_string).
if [[ $var != *sub_string ]]; then
    printf '%s\n' "var does not end with sub_string."
fii

```

# 2\. 数组

## 2.1 反转数组的顺序

启用extdebug 允许脚本访问BASH\_ARGV数组，该数组以逆序方式存储当前函数的参数。

> 注：需要bash 5.0 以上的shopt -s compat44 in +.

### 函数示例

```bash
reverse_array() {
    # Usage: reverse_array "array"
    shopt -s extdebug
    f()(printf '%s\n' "${BASH_ARGV[@]}"); f "$@"
    shopt -u extdebug
}

```

### 使用示例

```bash
$ reverse_array 1 2 3 4 5
5
4
3
2
1

$ arr=(red blue green)
$ reverse_array "${arr[@]}"
green
blue
red

```

## 2.2 移除数组中重复的元素

> 注：需要bash 4.0 以上版本  
> 注：List order may not stay the same.

### 函数示例

```bash
remove_array_dups() {
    # Usage: remove_array_dups "array"
    declare -A tmp_array

    for i in "$@"; do
        [[ $i ]] && IFS=" " tmp_array["${i:- }"]=1
    done

    printf '%s\n' "${!tmp_array[@]}"
}

```

### 使用示例

```bash
$ remove_array_dups 1 1 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 5
1
2
3
4
5

$ arr=(red red green blue blue)
$ remove_array_dups "${arr[@]}"
red
green
blue

```

## 2.3 随机返回数组中的元素

### 函数示例

```bash
random_array_element() {
    # Usage: random_array_element "array"
    local arr=("$@")
    printf '%s\n' "${arr[RANDOM % $#]}"
}

```

### 使用示例

```bash
$ array=(red green blue yellow brown)
$ random_array_element "${array[@]}"
yellow

# Multiple arguments can also be passed.
$ random_array_element 1 2 3 4 5 6 7
3

```

## 2.4 循环遍历一个数组

下面的样例代码中，每执行cycle一次将会顺序从数组arr中取出一个元素，并通过printf 输出到界面上。当到达arr的最后一个元素后，会重新跳回到第一个元素。

```bash
arr=(a b c d)

cycle() {
    printf '%s ' "${arr[${i:=0}]}"
    ((i=i>=${#arr[@]}-1?0:++i))
}

```

## 2.5 在两个值间来回切换

下面的用法与2.4的一致，只是一个不同的使用例子。

```bash
arr=(true false)

cycle() {
    printf '%s ' "${arr[${i:=0}]}"
    ((i=i>=${#arr[@]}-1?0:++i))
}

```

# 3\. 循环

## 3.1 在指定的数字范围内循环

可以替代seq

```bash
# Loop from 0-100 (no variable support).
for i in {0..100}; do
    printf '%s\n' "$i"
done

```

## 3.2 在变量指定的范围内循环

可以替代seq

```bash
# Loop from 0-VAR.
VAR=50
for ((i=0;i<=VAR;i++)); do
    printf '%s\n' "$i"
done

```

## 3.3 循环遍历一个数组

```bash
arr=(apples oranges tomatoes)

# Just elements.
for element in "${arr[@]}"; do
    printf '%s\n' "$element"
done

```

## 3.4 通过索引循环遍历一个数组

```bash
arr=(apples oranges tomatoes)

# Elements and index.
for i in "${!arr[@]}"; do
    printf '%s\n' "${arr[i]}"
done

# Alternative method.
for ((i=0;i<${#arr[@]};i++)); do
    printf '%s\n' "${arr[i]}"
done

```

## 3.5 循环遍历文件的内容

```bash
while read -r line; do
    printf '%s\n' "$line"
done < "file"

```

## 3.6 循环遍历文件及目录

```bash
# Greedy example.
for file in *; do
    printf '%s\n' "$file"
done

# PNG files in dir.
for file in ~/Pictures/*.png; do
    printf '%s\n' "$file"
done

# Iterate over directories.
for dir in ~/Downloads/*/; do
    printf '%s\n' "$dir"
done

# Brace Expansion.
for file in /path/to/parentdir/{file1,file2,subdir/file3}; do
    printf '%s\n' "$file"
done

# Iterate recursively.
shopt -s globstar
for file in ~/Pictures/**/*; do
    printf '%s\n' "$file"
done
shopt -u globstar

```

# 4\. 文件处理

> 注：bash低于4.4版本 不能正确处理二进制数据。

## 4.1 将文件内容读入到一个字符串

可以作为cat 命令的替代

```bash
file_data="$(<"file")"

```

## 4.2 按行将文件内容读入到一个数组

可以作为cat 命令的替代

```bash
# Bash <4 (discarding empty lines).
IFS=$'\n' read -d "" -ra file_data < "file"

# Bash <4 (preserving empty lines).
while read -r line; do
    file_data+=("$line")
done < "file"

# Bash 4+
mapfile -t file_data < "file"

```

## 4.3 获取文件的前N行

可以作为head 命令的替代

> 注：需要4.0以上版本的bash

### 函数示例

```bash
head() {
    # Usage: head "n" "file"
    mapfile -tn "$1" line < "$2"
    printf '%s\n' "${line[@]}"
}

```

### 使用示例

```bash
$ head 2 ~/.bashrc
# Prompt
PS1='➜ '

$ head 1 ~/.bashrc
# Prompt

```

## 4.4 获取文件的后N行

可以作为tail 命令的替代

> 注：需要4.0以上版本的bash

### 函数示例

```bash
tail() {
    # Usage: tail "n" "file"
    mapfile -tn 0 line < "$2"
    printf '%s\n' "${line[@]: -$1}"
}

```

### 使用示例

```bash
$ tail 2 ~/.bashrc
# Enable tmux.
# [[ -z "$TMUX"  ]] && exec tmux

$ tail 1 ~/.bashrc
# [[ -z "$TMUX"  ]] && exec tmux

```

## 4.5 获取文件的行数

可以作为 wc -l 命令的替代

### 函数示例(bash 4)

```bash
lines() {
    # Usage: lines "file"
    mapfile -tn 0 lines < "$1"
    printf '%s\n' "${#lines[@]}"
}

```

### 函数示例(bash 3)

这个方法比mapfile方法使用更少的内存，并且可以在bash 3 执行。但这个方法在处理大文件时比较慢。

```bash
lines_loop() {
    # Usage: lines_loop "file"
    count=0
    while IFS= read -r _; do
        ((count++))
    done < "$1"
    printf '%s\n' "$count"
}

```

### 使用示例

```bash
$ lines ~/.bashrc
48

$ lines_loop ~/.bashrc
48

```

## 4.6 获取目录中包含的文件或目录的数量

这是通过将glob的输出传递给函数然后计算参数的数量来实现的。

### 函数示例

```bash
count() {
    # Usage: count /path/to/dir/*
    #        count /path/to/dir/*/
    printf '%s\n' "$#"
}

```

### 使用示例

```bash
# Count all files in dir.
$ count ~/Downloads/*
232

# Count all dirs in dir.
$ count ~/Downloads/*/
45

# Count all jpg files in dir.
$ count ~/Pictures/*.jpg
64

```

## 4.7 创建一个空文件

可以作为touch 命令的替代

```bash
# Shortest.
>file

# Longer alternatives:
:>file
echo -n >file
printf '' >file

```

## 4.8 提取两个标记间的行

### 函数示例

```bash
extract() {
    # Usage: extract file "opening marker" "closing marker"
    while IFS=$'\n' read -r line; do
        [[ $extract && $line != "$3" ]] &&
            printf '%s\n' "$line"

        [[ $line == "$2" ]] && extract=1
        [[ $line == "$3" ]] && extract=
    done < "$1"
}

```

### 使用示例

```bash
# Extract code blocks from MarkDown file.
$ extract ~/projects/pure-bash/README.md '```sh' '```'
# Output here...

```

# 5\. 文件路径

## 5.1 获取文件路径中的目录

可以替代dirname 命令

### 函数示例

```bash
dirname() {
    # Usage: dirname "path"
    local tmp=${1:-.}

    [[ $tmp != *[!/]* ]] && {
        printf '/\n'
        return
    }

    tmp=${tmp%%"${tmp##*[!/]}"}

    [[ $tmp != */* ]] && {
        printf '.\n'
        return
    }

    tmp=${tmp%/*}
    tmp=${tmp%%"${tmp##*[!/]}"}

    printf '%s\n' "${tmp:-/}"
}

```

### 使用示例

```bash
$ dirname ~/Pictures/Wallpapers/1.jpg
/home/black/Pictures/Wallpapers

$ dirname ~/Pictures/Downloads/
/home/black/Pictures

```

## 5.2 获取文件路径中的basename

可以替代basename 命令

### 函数示例

```bash
basename() {
    # Usage: basename "path" ["suffix"]
    local tmp

    tmp=${1%"${1##*[!/]}"}
    tmp=${tmp##*/}
    tmp=${tmp%"${2/"$tmp"}"}

    printf '%s\n' "${tmp:-/}"
}

```

### 使用示例

```bash
$ basename ~/Pictures/Wallpapers/1.jpg
1.jpg

$ basename ~/Pictures/Wallpapers/1.jpg .jpg
1

$ basename ~/Pictures/Downloads/
Downloads

```

# 6\. 变量

## 6.1 分配并使用一个变量

```bash
$ hello_world="value"

# Create the variable name.
$ var="world"
$ ref="hello_$var"

# Print the value of the variable name stored in 'hello_$var'.
$ printf '%s\n' "${!ref}"
value

```

在 bash 4.3+以上版本:

```bash
$ hello_world="value"
$ var="world"

# Declare a nameref.
$ declare -n ref=hello_$var

$ printf '%s\n' "$ref"
value

```

## 6.2 基于另一个变量的值命名新的变量

```bash
$ var="world"
$ declare "hello_$var=value"
$ printf '%s\n' "$hello_world"
value

```

# 7\. 转义序列

与我们一般的想法相反，使用原始的转义序列并不会带来问题。使用 tput 抽象系统的ANSI序列就像手工打印一样麻烦。更糟糕的是，tput 实际上在不同的系统中并不是兼容的. 有许多tput变体，每个变体都有不同的命令和语法 (例如在FreeBSD 系统上使用tput setaf 3)。 原始的转义序列会更好用。

## 7.1 文本颜色

> 注：序列中的RGB值仅在真彩色的终端上才有效

| 序列                     | 说明             | 参数值   |
| ---------------------- | -------------- | ----- |
| \\e\[38;5;<NUM>m       | 设置文本前景色.       | 0-255 |
| \\e\[48;5;<NUM>m       | 设置文本背景色.       | 0-255 |
| \\e\[38;2;<R>;<G>;<B>m | 设置文本前景色为RGB颜色. | R,G,B |
| \\e\[48;2;<R>;<G>;<B>m | 设置文本背景色为RGB颜色. | R,G,B |

## 7.2 文本属性

| 序列            | 说明     |
| ------------- | ------ |
| \`\`\`\\e\[m  | \`\`\` |
| \`\`\`\\e\[1m | \`\`\` |
| \`\`\`\\e\[2m | \`\`\` |
| \`\`\`\\e\[3m | \`\`\` |
| \`\`\`\\e\[4m | \`\`\` |
| \`\`\`\\e\[5m | \`\`\` |
| \`\`\`\\e\[7m | \`\`\` |
| \`\`\`\\e\[8m | \`\`\` |
| \`\`\`\\e\[9m | \`\`\` |

## 7.3 光标移动

| 序列                    | 说明            | 参数值         |
| --------------------- | ------------- | ----------- |
| \\e\[<LINE>;<COLUMN>H | 光标移动到绝对位置.    | line,column |
| \\e\[H                | 光标移动到原点(0,0). |             |
| \\e\[<NUM>A           | 光标向上移动N行.     | num         |
| \\e\[<NUM>B           | 光标向下移动N行.     | num         |
| \\e\[<NUM>C           | 光标向右移动N行.     | num         |
| \\e\[<NUM>D           | 光标向左移动N行.     | num         |
| \\e\[s                | 保存光标位置.       |             |
| \\e\[u                | 恢复光标位置.       |             |

## 7.4 删除文本

| 序列            | 说明                |
| ------------- | ----------------- |
| \\e\[K        | 删除当前光标位置到行末的所有文本. |
| \\e\[1K       | 删除当前光标位置到行首的所有文本. |
| \\e\[2K       | 删除当前行.            |
| \\e\[J        | 删除当前行到屏幕底部的所有行.   |
| \\e\[1J       | 删除当前行到屏幕顶部的所有行.   |
| \\e\[2J       | 清除屏幕.             |
| \\e\[2J\\e\[H | 清除屏幕，光标回到原点(0,0). |

# 8\. 参数扩展

## 8.1 变量的间接访问

| 参数        | 说明                                                       |
| --------- | -------------------------------------------------------- |
| ${!VAR}   | 访问名字为VAR的值的变量.                                           |
| ${!VAR\*} | 将名字以VAR的值开头的变量值扩展为列表，并以 ITS 分割                           |
| ${!VAR@}  | 将名字以VAR的值开头的变量值扩展为列表，并以 ITS 分割,如果是双引号，则每个变量名称都会扩展为单独的单词. |

## 8.2 替换

| 参数                      | 说明                           |
| ----------------------- | ---------------------------- |
| ${VAR#PATTERN}          | 移除VAR中从开始到第一次与模式匹配的左边的字符.    |
| ${VAR##PATTERN}         | 移除VAR中从开始到最后一次与模式匹配的左边的字符.   |
| ${VAR%PATTERN}          | 移除VAR中从结尾开始到第一次与模式匹配的右边的字符.  |
| ${VAR%%PATTERN}         | 移除VAR中从结尾开始到最后一次与模式匹配的右边的字符. |
| ${VAR/PATTERN/REPLACE}  | 替换第一次匹配的字符.                  |
| ${VAR//PATTERN/REPLACE} | 替换所有匹配的字符.                   |
| ${VAR/PATTERN}          | 删除第一次匹配的字符.                  |
| ${VAR//PATTERN}         | 删除所有匹配的字符.                   |

## 8.3 长度

| 参数           | 说明          |
| ------------ | ----------- |
| ${#VAR}      | 变量中包含的字符长度. |
| ${#ARR\[@\]} | 数组中包含的元素的个数 |

## 8.4 扩展

| 参数                    | 说明                          |
| --------------------- | --------------------------- |
| ${VAR:OFFSET}         | 从变量中移除开头的OFFSET个字符.         |
| ${VAR:OFFSET:LENGTH}  | 获得从OFFSET字符之后LENGTH个字符的字符串. |
| ${VAR:: OFFSET}       | 获取变量的开头的OFFSET个字符.          |
| ${VAR:: -OFFSET}      | 从变量中删除结尾的OFFSET个字符.         |
| ${VAR: -OFFSET}       | 从变量中获取结尾的OFFSET个字符.         |
| ${VAR:OFFSET:-OFFSET} | 从变量中删除从OFFSET字符之后LENGTH个字符. |

## 8.5 调整大小写

| 参数         | 说明        | 版本要求    |
| ---------- | --------- | ------- |
| ${VAR^}    | 首字符大写     | bash 4+ |
| ${VAR^^}   | 所有字符大写    | bash 4+ |
| ${VAR,}    | 首字符小写     | bash 4+ |
| ${VAR,,}   | 所有字符小写    | bash 4+ |
| ${VAR\~}   | 首字符大小写反转  | bash 4+ |
| ${VAR\~\~} | 所有字符大小写反转 | bash 4+ |

## 8.6 缺省值

| 参数             | 说明                               |
| -------------- | -------------------------------- |
| ${VAR:-STRING} | 如果VAR为空 或者没有设置，则使用STRING作为它的值.   |
| ${VAR-STRING}  | 如果VAR为空，则使用STRING作为它的值.          |
| ${VAR:=STRING} | 如果VAR为空 或者没有设置，则将变量VAR设置为STRING. |
| ${VAR=STRING}  | 如果VAR没有设置，则将变量VAR设置为STRING.      |
| ${VAR:+STRING} | 如果VAR不为空，则使用STRING作为它的值.         |
| ${VAR+STRING}  | 如果VAR已经设置，则使用STRING作为它的值.        |
| ${VAR:?STRING} | 如果VAR为空，则显示一个错误.                 |
| ${VAR?STRING}  | 如果VAR没有设置，则显示一个错误.               |

# 9\. 花括号扩展

## 9.1 范围

```bash
# 用法: {<START>..<END>}

# 打印数字 1-100.
echo {1..100}

# 打印浮点数范围.
echo 1.{1..9}

# 打印字符 a-z.
echo {a..z}
echo {A..Z}

# 嵌套.
echo {A..Z}{0..9}

# 打印用零填充的数字..
# 版本要求: bash 4+
echo {01..100}

# 更改增量
# 用法: {<START>..<END>..<INCREMENT>}
# 版本要求: bash 4+
echo {1..10..2}  # 以2为增量.

```

## 9.2 字符串列表

```bash
echo {apples,oranges,pears,grapes}

# 使用示例:
# 删除~/Downloads/ 目录下的 Movies, Music 和 ISOS文件夹 .
rm -rf ~/Downloads/{Movies,Music,ISOS}

```

# 10\. 条件表达式

## 10.1 文件条件判断

| 表达式 | 值    | 说明                                   |
| --- | ---- | ------------------------------------ |
| \-a | file | 文件存在                                 |
| \-b | file | 文件存在且是块设备文件（block special file）      |
| \-c | file | 文件存在且是字符设备文件（character special file） |
| \-d | file | 文件存在且是一个目录                           |
| \-e | file | 文件存在                                 |
| \-f | file | 文件存在且是一个普通文件                         |
| \-g | file | 文件存在且已经设置set-group-id位               |
| \-h | file | 文件存在并且是符号链接.                         |
| \-k | file | 文件存在且已经设置sticky-bita位                |
| \-p | file | 文件存在并且是命名管道 (FIFO).                  |
| \-r | file | 文件存在且可读                              |
| \-s | file | 文件存在且其大小大于零.                         |
| \-t | file | 文件描述符是打开的并且引用到一个终端.                  |
| \-u | file | 文件存在且其set-user-id位已设置.               |
| \-w | file | 文件存在且可写.                             |
| \-x | file | 文件存在且可执行.                            |
| \-G | file | 文件存在且拥有者是一个有效组ID.                    |
| \-L | file | 文件存在并且是符号链接.                         |
| \-N | file | 文件存在且自上次读取后已被修改.                     |
| \-O | file | 文件存在并且拥有者是一个有效用户ID.                  |
| \-S | file | 文件存在且是套接字.                           |

## 10.2 文件比较

| 表达式            | 说明                                                |
| -------------- | ------------------------------------------------- |
| file -ef file2 | 两个文件都引用相同的inode和设备编号.                             |
| file -nt file2 | 是否 file 比 file2更新 (使用修改时间) 或者 file 存在而 file2 不存在. |
| file -ef file2 | 是否 file 比 file2更旧 (使用修改时间) 或者 file2 存在而 file 不存在. |

## 10.3 变量条件

| 表达式 | 值   | 说明            |
| --- | --- | ------------- |
| \-o | opt | 是否启用了shell选项. |
| \-v | var | 是否变量具有指定的值.   |
| \-R | opt | 是否变量是一个名称引用.  |
| \-z | opt | 是否字符串的长度为零.   |
| \-n | opt | 是否字符串的长度不为0   |

## 10.3 变量比较

| 表达式         | 说明                 |
| ----------- | ------------------ |
| var = var2  | 等于                 |
| var == var2 | 等于 (同义词 =).        |
| var != var2 | 不等于                |
| var < var2  | 小于 (以ASCII字母顺序排列.) |
| var > var2  | 大于 (以ASCII字母顺序排列.) |

# 11\. 算术运算符

## 11.1 赋值

| 操作符 | 说明             |
| --- | -------------- |
| \=  | 对变量的值进行初始化或者修改 |

## 11.2 算术运算符

| 操作符  | 说明          |
| ---- | ----------- |
| +    | 加           |
| \-   | 减           |
| \*   | 乘           |
| /    | 除           |
| \*\* | 幂运算         |
| %    | 模           |
| +=   | 加等于（增加一个变量） |
| \-=  | 减等于（减少一个变量） |
| \*=  | 乘等于（乘一个变量）  |
| /=   | 除等于（除一个变量）  |
| \=   | 模等于（先取模后赋值） |

## 11.2 位运算

| 操作符 | 说明   |
| --- | ---- |
| <<  | 按位左移 |
| <<  | 按位左移 |
| <<  | 按位左移 |
| <<  | 按位左移 |
| <<  | 按位左移 |
| <<  | 按位左移 |
| <<  | 按位左移 |
| <<  | 按位左移 |
| <<  | 按位左移 |
| <<  | 按位左移 |
| <<  | 按位左移 |

# \---The End ---