前阵子写了不少 bash 脚本,有些代码片段值得一记。有以下几项内容:

  • 获取当前脚本文件所在路径
  • 字符串 startsWith 和 endsWith
  • 判断字符串内容是否是数字
  • 获取字符串的子串
  • if 语句的几个判断条件

获取当前脚本文件所在的路径

用户执行脚本时,用户所在的目录,也就是 current working directory,可以通过执行 pwd 或者 bash 的内置变量 $PWD 获取。

有时用户执行脚本时,需要拿到脚本文件本身的路径,就稍微麻烦一些。

CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"

字符串 startsWith 和 endsWith

使用 * 号来实现这两个小功能。

如下,判断是否以 sub_string 开头。

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

判断是否以 sub_string 结尾

if [[ $var == *sub_string ]]; then
    printf '%s\n' "var ends with sub_string."
fi
if [[ $var != *sub_string ]]; then
    printf '%s\n' "var does not end with sub_string."
fi

isNumber

判断字符串的内容是否是个数字,比如 "1234" 为真,"abcd""12abcd" 为假。

isNumber() {
  local str="$1"
  local re="^[0-9]+$"
  [[ "$str" =~ $re ]]
}

使用 isNumber 的例子:

#!/bin/bash
isNumber() {
  local str="$1"
  local re="^[0-9]+$"
  [[ "$str" =~ $re ]]
}
tests() {
  isNumber "$1" && echo "yes" || echo "no"
}
tests ""
tests "abc"
tests "abc123"
tests "1acb23"
tests "123"
tests "455"

输出结果:

no no no no yes yes

如果要允许带小数点的格式,那么要把上述代码中的正则表达式换成 ^[0-9]+([.][0-9]+)?$

Stackoverflow – How do I test if a variable is a number in Bash?

获取字符串的子串

有很多方法可以做字符串分割,比如用 cut 命令,awk 命令等等。这里记录的是我一直记不住的一个代码片段。

比如一个字符串变量是 var=hello.world-1234.txt,我们想要根据字符串中的点和横线来分割,获取子字符串。

${var#pattern} 从字符串开始位置,去除最短匹配 pattern 的部分。例如 ${var#*.},pattern 中的星号是通配符,结果就是匹配到第一个 . 之前的部分被去掉,获取到的字符串是 world-1234.txt

${var##pattern} 从字符串开始位置,去除最长匹配 pattern 的部分。
${var%pattern} 从字符串结尾位置,去除最短匹配 pattern 的部分。
${var%%pattern} 从字符串结尾位置,去除最长匹配 pattern 的部分。

var=hello.world-1234.txt
echo "${var#*.}"
echo "${var##*.}"
echo "${var%.*}"
echo "${var%%.*}"

结果是

world-1234.txt     // 从前向后截掉最短匹配 *. 的子串
txt                // 从前向后截掉最长匹配 *. 的字串
hello.world-1234   // 从后向前截掉最短匹配 .* 的内容
hello              // 从后向前截掉最长匹配 .* 的内容

如果想把 hello.world 截取出来,可以用 ${var%-*}。由于 var 里只有一个 -,所以从前往后或者从后往前,找到的都是一个位置,${var%%-*} 同样得到 hello.world

if 判断条件

-e 文件是否存在(万物皆文件)
-d 是否是目录并且存在
-s 文件是否存在并且大小不为 0
-f 文件是否存在并且是普通文件
-h 文件是否存在并且是符号链接
-L 文件是否存在并且是符号链接
-z 字符串长度是否为 0
-n 字符串长度是否不为 0

要注意以下几点:

  • 不论是普通文件,软链接,目录,块设备等等,都是「文件」,-e 测试都为真。
  • -f 测试一个普通文件,或者一个软链接,结果都为真。要确定是否是软链接,用 -h-L