shell 语法

语法详解

概论

shell:通过命令行与操作系统沟通的语言。脚本可在命令行中执行或组成一个文件复用。常见脚本:

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • zsh

Linux 系统中一般默认使用 bash,以下以 bash 中的语法为例。文件开头需要写 #! /bin/bash,指明 bash 为脚本解释器。新建一个 test.sh 文件,内容如下:

1
2
#! /bin/bash
echo "Hello World!"

可执行文件

1
2
3
~ chmod +x test.sh  # 使脚本具有可执行权限
~ ./test.sh  # 当前路径下执行
~ /home/wtyang/test.sh  # 绝对路径下执行

解释器执行,不需要有可执行权限

1
~ bash test.sh

注释

每行中 # 之后的内容均是注释。

1
echo 'Hello World'  # 这是注释

多行注释格式如下,其中 EOF 可以换成其它任意字符串,也可以不加冒号。

1
2
3
4
5
:<<EOF
第一行注释
第二行注释
第三行注释
EOF

变量

定义变量,不需要加 $ 符号

1
2
3
name1='yxc'  # 单引号定义字符串
name2="yxc"  # 双引号定义字符串
name3=yxc    # 也可以不加引号,同样表示字符串

使用变量,需要加上 $ 符号,或者 ${} 符号。花括号是可选的,主要为了帮助解释器识别变量边界。

1
2
3
4
name=yxc
echo $name  # 输出yxc
echo ${name}  # 输出yxc
echo ${name}acwing  # 输出yxcacwing

使用 readonly 或者 declare 可以将变量变为只读。

1
2
3
4
name=yxc
readonly name
declare -r name  # 两种写法均可
name=abc  # 会报错,因为此时name只读

unset 可以删除变量。

1
2
3
name=yxc
unset name
echo $name  # 输出空行

变量类型分为:

  1. 自定义变量(局部变量):子进程不能访问的变量

  2. 环境变量(全局变量):子进程可以访问的变量

自定义变量改成环境变量:

1
2
3
~ name=yxc  # 定义变量
~ export name  # 第一种方法
~ declare -x name  # 第二种方法

环境变量改为自定义变量:

1
2
~ export name=yxc  # 定义环境变量
~ declare +x name  # 改为自定义变量

字符串可以用单引号,也可以用双引号,也可以不用引号。

单引号与双引号的区别:

  • 单引号中的内容会原样输出,不会执行、不会取变量;
  • 双引号中的内容可以执行、可以取变量;
1
2
3
name=yxc  # 不用引号
echo 'hello, $name \"hh\"'  # 单引号字符串,输出 hello, $name \"hh\"
echo "hello, $name \"hh\""  # 双引号字符串,输出 hello, yxc "hh"

获取字符串长度

1
2
name="yxc"
echo ${#name}  # 输出 3

提取子串

1
2
name="hello, yxc"
echo ${name:0:5}  # 提取从 0 开始的 5 个字符

默认变量

在执行 shell 脚本时,可以向脚本传递参数。$1 是第一个参数,$2 是第二个参数,以此类推。特殊的,$0 是文件名(包含路径)。脚本传递参数时,参数个数超过一位需要用大括号括起来。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
echo "文件名:"$0
echo "第一个参数:"$1
echo "第二个参数:"$2
echo "第三个参数:"$3
echo "第四个参数:"$4

~ ./test.sh 1 2 3 4
文件名:./test.sh
第一个参数:1
第二个参数:2
第三个参数:3
第四个参数:4
参数 说明
$# 代表文件传入的参数个数,如上例中值为 4
$* 由所有参数构成的用空格隔开的字符串,如上例中值为 "$1 $2 $3 $4"
$@ 每个参数分别用双引号括起来的字符串,如上例中值为 "$1" "$2" "$3" "$4"
$$ 脚本当前运行的进程 ID
$? 上一条命令的退出状态(注意不是 stdout,而是 exit code)。0 表示正常退出,其他值表示错误
$(command) 返回command 这条命令的 stdout(可嵌套)
command\ 返回 command 这条命令的 stdout(不可嵌套)

数组

数组中可以存放多个不同类型的值,只支持一维数组,初始化时不需要指明数组大小。数组下标从0开始。

  • 定义

数组用小括号表示,元素之间用空格隔开。也可以直接定义数组中某个元素的值。

1
2
3
4
5
array=(1 abc "def" yxc) # 等价如下
array[0]=1
array[1]=abc
array[2]="def"
array[3]=yxc
  • 读取数组中某个元素的值

格式为 ${array[index]},例如

1
2
3
4
5
array=(1 abc "def" yxc)
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}
  • 读取整个数组

格式:

1
2
${array[@]}  # 第一种写法
${array[*]}  # 第二种写法
  • 数组长度

类似于字符串

1
2
${#array[@]}  # 第一种写法
${#array[*]}  # 第二种写法

expr 命令

expr命令用于求表达式的值,格式为 expr 表达式

  • 字符串表达式
    • length STRING: 返回 STRING 的长度
    • index STRING CHARSET: CHARSET 中任意单个字符在 STRING 中最前面的字符位置,下标从 1 开始。如果在 STRING 中完全不存在 CHARSET 中的字符,则返回 0
    • substr STRING POSITION LENGTH: 返回 STRING 字符串中从 POSITION 开始,长度最大为 LENGTH 的子串。如果 POSITIONLENGTH 为负数,0 或非数值,则返回空字符串。

示例:

1
2
3
4
5
str="Hello World!"

echo `expr length "$str"`  # ``不是单引号,表示执行该命令,输出12
echo `expr index "$str" aWd`  # 输出7,下标从1开始
echo `expr substr "$str" 2 3`  # 输出 ell
  • 整数表达式

作业