跟着 deno 安装脚本学 shell

819 阅读4分钟

最近在看 deno,发现它的安装脚本写的非常简洁易懂,作为一名前端,之前一直对 shell 脚本半懂不懂、似懂非懂,但是自从看了 deno 的脚本之后,突然觉得写 shell 逻辑也可以这么舒服,里面基本上都是使用简单的 if 语句来实现全部功能的。

任何一门编程语言中都有 if 条件判断语句,在 shell 脚本编程中,自然也少不了这个场景,例如:

  • 判断目录是否存在
  • 判断命令是否执行成功
  • 判断文件是否可写
  • ……

shell 脚本中,条件判断语句的基本结构是:

if command
then
  commands
fi

但很多人喜欢下面的写法,因为看起来更像高级编程语言的写法:

if command; then
  commands
fi

在本文的代码中,也采用这种写法。一般来讲,if 后面的语句是一个布尔类型的值,即:TRUE 或者 FALSE,但是在 shell 中却并非如此,而是一个命令,例如:

if pwd; then
  echo "run success"
fi

shell 中的 if 语句会执行 if 后面的命令,如果该命令的退出状态码为 0(表示命令成功运行),那么 then 后面的命令就会被执行。

那在 shell 中,怎么做数值比较(例如 5>4),或者字符串比较(例如 'a' > 'A'),或者目录是否存在这样判断呢?别急,本文就是讲这个的,在 shell 中,叫做 test 命令。

test 命令

test 命令有两种语法,第一种是:

if test condition; then
  commands
fi

第二种是:

if [ condition ]; then
  commands
fi

这里尤其需要注意的是:第一个方括号里面必须要用空格,否则会报错!即:

  • [ 的后面必须要有空格,即:[
  • ] 的前面必须要有空格,即: ]

接下来,我们来学习一些常见的判断场景。

数值比较

在 JavaScript 中,我们经常会这样写:

if (count > 0) {
  // do something
}

判断变量 count 和数值 0 的大小,在 shell 中的写法是这样的:

if [ $value -gt 0 ]; then
  # do something
fi

即环境变量和数字 0 的比较,在 deno 的安装脚本中就有数值比较的经典案例:

接下来上机验证一下:

$ value=3
$ if [ $value -gt 0 ]; then
  echo "$value is than 0"
fi
3 is than 0

可以看到,输出了正确的结果。常用的语法:

语法解释助记单词
n1 -eq n2n1 是否等于 n2equal to
n1 -ne n2n1 是否不等于 n2not equal
n1 -ge n2n1 是否大于等于 n2greater than or equal
n1 -gt n2n1 是否大于 n2greater than
n1 -le n2n1 是否小于等于 n2less than or equal
n1 -lt n2n1 是否小于 n2less than

但是非常遗憾的是,这种方式只能比较整数,如果是浮点数,例如 3.5 的话,就会报错:

$ value=3.5                
$ if [ $value -gt 0 ]; then
  echo "$value is than 0"
fi
[: integer expression expected: 3.5

你可能会想,shell 脚本编程也太弱鸡了吧,别慌,还有更好的数值比较方法,即双括号语法:

if (( expression )); then
  # do something
fi

在双括号里面,可以直接写数学表达式,例如加减乘除等等,我们来验证一下:

$ value=3.5                
$ if (( $value > 0 )); then
  echo "$value is than 0"
fi
3.5 is than 0

能够正确处理浮点数!还可以处理更复杂的运算,例如:

$ value=3.5                
$ if (( $value * 2 + 1 == 8 )); then
  echo "result is 8"
fi
result is 8

怎么样?有了双括号,是不是进行数值比较更简单、更方便了呢?

字符串比较

上一节中讲到,数值比较可以在条件表达式中用 -eq-gt 这种语法,如果是字符串的话,则不能这么写,要用 >=< 这种:

if [ $value = hello ]; then
  # do something
fi

deno 的安装脚本中就有字符串比较的经典案例:

如果当前操作系统是 Windows 的话,就设置 target 的值。我们上机实验一下:

$ value=hello
$ if [ $value = hello ]; then
  echo "hello"  
fi
hello

比较数字用 -eq,比较字符串用 = ,这种设计还蛮反直觉的,而且如果在 [ ] 中用 >< 比较字符串的话,需要用反斜线转义,不能直接写,例如:

if [ $value1 > $value2 ]; then
  echo $value1 greater than $value2
fi

这样写不会报错,但是结果是错误的,因为在这里 > 表示重定向,而不是比较大小,需要这么写:

if [ $value1 \> $value2 ]; then
  echo $value1 greater than $value2
fi

这也太恶心了,太不优雅了吧。是的,不止你一个人这么觉得,大家都这么认为,于是就有了另外一种比较字符串的语法,即双方括号语法:

if [[ $value1 > $value2 ]]; then
  echo $value1 greater than $value2
fi

这样子看起来就舒服多啦,双小括号表示数值比较,双中括号表示字符串比较,简单易懂。关键双中括号还提供了强大的模式匹配功能:

if [[ $value == hello* ]]; then
  echo $value1 prefix is hello
fi

这样只要 value 的值是以 hello 为前缀的,就都符合条件。

文件比较

讲完了数值比较和字符串比较,在 shell 编程中,最实用的其实是文件比较,它允许用户测试系统中文件和目录的状态,例如:

$ directory=/home/keliq
$ if [ -d $directory ]; then
  echo directory exits
fi

deno 的安装脚本中就有文件比较的经典案例:

如果目录不存在,就创建该目录,-d 可以用于检查目录是否存在,-f 可以用于检查文件是否存在,如果不区分目录或文件,则可以用 -e,常见的语法如下:

语法含义
-e file检查 file 是否存在
-d file检查目录 file 是否存在
-f file检查文件 file 是否存在
-r file检查 file 是否只读
-s file检查 file 是否非空
-w file检查 file 是否可写
-x file检查 file 是否可执行
file1 -nt file2检查 file1 是否比 file2 新
file1 -ot file2检查 file1 是否比 file2 旧

总结

到这里,我相信 shell 中的 if 语句大家都已经能够掌握了,口诀:

  • 数值比较双圆括号
  • 字符串比较双方括号
  • 文件比较杠def