Shell语法

发布于 2020 年 09 月 28 日 | 更新于 2022 年 04 月 03 日

特殊变量

获取所有参数:

$#参数个数

$$当前进程的id

数组

a=(1 2 3)用空格分割

下标访问:${a[$i]}

Bash参数

脚本第一行#!<shell path> [options]指定用哪个shell来执行该脚本,常用选项(options)如下:

-e:表示任意指令返回非真值(非0值)时结束脚本,写作#!/bin/bash -e

更多选项参考bash -c "help set"online man: set(1p)更详细

if

if本质上是在判断后续命令返回值:0为真,非0为假

truefalse是两个命令,true返回0,false返回1

if ls; then echo 1; fi  # 真
if return 1; then echo 1; fi  # 假
if sl; then echo 1; fi  # 直接报错 command not found: sl
if true; then echo 1; fi  # 真
if false; then echo 1; fi  # 假

变量

shell变量本质上就是宏替换,可以将命令赋给一个变量,然后通过$+变量名来执行命令

var=ls  # z='ls' z="ls" 都是一样
$var  # 执行 ls

所以:可以将truefalse赋给一个变量,然后放在if后面进行判断

var=true
if $var; then echo 1; fi  # 真
var=false
if $var; then echo 1; fi  # 假

双引号

bash中的所有变量最好都用双引号括起来

在打印一个变量时,如果含有空白字符(空格、制表、换行等),通常会用双引号括起来,否则会被shell按通配符进行解析

echo `ls -l`  # 无换行
echo "`ls -l`"  # 正常显示换行

Outside of double quotes, $var takes the value of var, splits it into whitespace-delimited parts, and interprets each part as a glob (wildcard) pattern. Unless you want this behavior, always put $var inside double quotes: "$var".

不用双引号的话,变量会被拆分为多个部分(以空白字符为分割),每个部分被当作一个通配符(wildcard)进行解析

Double quotes for variable and command substitution

参考:

条件表达式

条件表达式主要有几种形式:ref

Test Constructs

[ 和 test

[ is another name for the traditional test command.

关于if [ EXPRESSION ],左右方括号必须要隔空格的原因是:Shell将[当作一条指令

which [
[: shell built-in command
whereis [
[: /usr/bin/[ /usr/share/man/man1/[.1.gz
ls -l /usr/bin/\[
-rwxr-xr-x 1 root root 59736 Sep  5  2019 '/usr/bin/['
# 可以看到'['是一个可执行文件

因此,也可以直接在交互Shell中测试[ EXPRESSION ]的返回值($?)

由于&&||被Shell用于连接两条命令,因此,[ EXPRESSION ]中出现&&||时,会被认为是第二条指令,然后报错找不到]

[ 1 && 2 ] # False(返回值非0)
[: ']' expected # 报错
[ 1 ] && [ 2 ] # True(返回值为0)

[[

[[test命令的一种改版,可以使用&&||

正则匹配:使用=~来正则地比较字符串(好像只用=也支持正则),字符串在左,正则模式在右

((

主要用于算数运算,支持C-style的自增自减(++/–)

The Double-Parentheses Construct

ARITHMETIC EVALUATION

a=$(( 3 + 5 ))  # shell里面这种‘a’和‘=’分开的话,一般情况下a会被当成指令
(( a++ ))
echo $a  # 9

test 操作符

更多参见man bashCONDITIONAL EXPRESSIONS章节

参数扩展

${parameter:-word}:使用默认值,如果parameter不存在,就以word作为其值

更多参考man bashParameter Expansion小节

杂项

$?:这个变量保存了上一条指令返回值

赋值=两边不能有空格判断=两边必须要有空格

判断是否传入参数(参数是否存在):直接$1

函数获取返回值$(function name)

全局变量???

管道命令执行顺序

用管道连接的命令是同时执行的

比如ps a | grep bash的执行结果中,会出现grep的进程

➜  ~ ps a | grep bash
  263 pts/0    Ss     0:00 -bash
  811 pts/0    S+     0:00 grep bash

说明在ps在执行打印进程信息的时候,grep也在执行了,也就是说psgrep是同时执行的

只不过grep执行到需要输入的时候就会停下来(状态S+),等待I/O(ps的标准输出)

Zsh和Bash的兼容性问题

Zsh并不是完全兼容Bash

如果要完全兼容,使用emulate bash 或文件开头添加#!/usr/bin/bash(直接指定用bash执行该脚本)

目前遇到的不兼容情况:

  1. 条件表达式中,判断相等,Bash支持双等号==,而Zsh只支持单等号=
  2. curl命令无法正常运行

Shell中的字符串变量更像是C语言中的宏定义,运行时直接替换到目标位置,如果包含空格就容易引起歧义,因此通常将变量写在双引号内"$a"

算数运算在((…))中进行,如((i=i+1))

算术运算

Bash arithmetic is limited to integers.

Problem with Bash Script array arithmetic for simple sine wave generator