Linux_3 shell语法

概论

shell是什么

  • shell是我们通过命令行与操作系统沟通的语言。

  • shell脚本可以直接在命令行中执行,也可以将一套逻辑组织成一个文件,方便复用。

  • AC Terminal中的命令行可以看成是一个“shell脚本在逐行执行”。

  • Linux中常见的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文件,内容如下:
#! /bin/bash
echo "Hello World!"

运行方式

作为可执行文件

# 作为可执行文件执行需要权限
acs@9e0ebfcd82d7:~$ ls -l test.sh # 查看权限
acs@9e0ebfcd82d7:~$ chmod +x test.sh  # 使脚本具有可执行权限
acs@9e0ebfcd82d7:~$ ./test.sh  # 当前路径下执行
Hello World!  # 脚本输出
acs@9e0ebfcd82d7:~$ /home/acs/test.sh  # 绝对路径下执行
Hello World!  # 脚本输出
acs@9e0ebfcd82d7:~$ ~/test.sh  # 家目录路径下执行
Hello World!  # 脚本输出

用解释器执行

# 解释器执行不需要有可执行权限
acs@9e0ebfcd82d7:~$ bash test.sh
Hello World!  # 脚本输出

注释

单行注释

  • 每行中#之后的内容均是注释。
# 这是一行注释
echo 'Hello World'  #  这也是注释

多行注释

# 格式:
:<<EOF
	第一行注释
	第二行注释
	第三行注释
EOF

# 其中EOF可以换成其它任意字符串。例如:
:<<abc
	第一行注释
	第二行注释
	第三行注释
abc

:<<!
	第一行注释
	第二行注释
	第三行注释
!

变量

定义变量

  • 定义变量,不需要加$符号,例如:
# 定义变量时,等号两边不能有空格
name1='hf'  # 单引号定义字符串
name2="hf"  # 双引号定义字符串
name3=hf    # 也可以不加引号,同样表示字符串

使用变量

  • 使用变量,需要加上$符号,或者${}符号。
  • 花括号是可选的,主要为了帮助解释器识别变量边界。
name=hf
echo $name  # 输出yxc
echo ${name}  # 输出yxc
echo ${name}acwing  # 输出yxcacwing

只读变量

  • 使用readonly或者declare可以将变量变为只读。
name=hf
readonly name
declare -r name  # 两种写法均可

name=abc  # 会报错,因为此时name只读

删除变量

  • unset可以删除变量。
# 被声明为只读的变量无法被unset删除
name=hf
unset name
echo $name  # 输出空行

变量类型

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

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

# 自定义变量改成环境变量:
# 默认变量是局部变量(自定义变量)
acs@9e0ebfcd82d7:~$ name=hf  # 定义变量
acs@9e0ebfcd82d7:~$ export name  # 第一种方法
acs@9e0ebfcd82d7:~$ declare -x name  # 第二种方法

# 环境变量改为自定义变量:
acs@9e0ebfcd82d7:~$ export name=hf  # 定义环境变量
acs@9e0ebfcd82d7:~$ declare +x name  # 改为自定义变量

war:[start]
tmux经ctrl a + %后分屏的两个界面实际上是两个bash,在一个bash中自定义的bash变量仅可以被当前bash访问,通过bash命令开启的子进程也无法访问。export后变量变为环境变量,就可以被全局访问。
war:[end]

字符串

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

  • 单引号与双引号的区别:

    • 单引号中的内容会原样输出,不会执行、不会取变量;
    • 双引号中的内容可以执行、可以取变量;
name=yxc  # 不用引号
echo 'hello, $name \"hh\"'  # 单引号字符串,输出 hello, $name \"hh\"
echo "hello, $name \"hh\""  # 双引号字符串,输出 hello, yxc "hh"
# 字符串中,不加引号和双引号效果相同
echo hello, $name \"hh\"  # 无引号字符串,输出 hello, yxc "hh"
  • 获取字符串长度
name="yxc"
echo ${#name}  # 输出3
  • 提取子串
name="hello, yxc"
echo ${name:0:5}  # 提取从0开始的5个字符

默认变量

文件参数变量

  • 在执行sh脚本时,可以向脚本传递参数。$1是第一个参数,$2是第二个参数,以此类推。特殊的,$0是文件名(包含路径)。例如:

  • 创建文件test.sh:

#! /bin/bash

echo "文件名:"$0
echo "第一个参数:"$1
echo "第二个参数:"$2
echo "第三个参数:"$3
echo "第四个参数:"$4
# 如果取的是第10个输入参数的话,一定需要加上{},否则,$10是输出第一参数后再输出一个0,如下:
echo ${10}
echo ${11}
  • 然后执行该脚本:
acs@9e0ebfcd82d7:~$ chmod +x test.sh
acs@9e0ebfcd82d7:~$ ./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开始

定义

  • 数组用小括号表示,元素之间用空格隔开。例如:
array=(1 abc "def" yxc)
  • 也可以直接定义数组中某个元素的值:
array[0]=1
array[1]=abc
array[2]="def"
array[3]=yxc

读取数组中某个元素的值

  • 格式:
${array[index]} # 变量替换

war:[start]
$(sdout) # 注意区分!

# $(command):返回command这条命令的stdout(可嵌套)
# ${sdout}:变量替换,取变量的值

war:[end]

  • 例如:
array=(1 abc "def" yxc)
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}

读取整个数组

  • 格式:
${array[@]}  # 第一种写法
${array[*]}  # 第二种写法
  • 例如:
array=(1 abc "def" yxc)

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

数组长度

  • 类似于字符串
${#array[@]}  # 第一种写法
${#array[*]}  # 第二种写法
  • 例如:
array=(1 abc "def" yxc)

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

表达式运算命令expr

概述

  • expr命令用于求表达式的值,格式为:
expr 表达式
  • 表达式说明:
    • 用空格隔开每一项
    • 用反斜杠放在sh特定的字符前面(发现表达式运行错误时,可以试试转义)
    • 对包含空格和其他特殊字符的字符串要用引号括起来
    • expr会在stdout中输出结果。如果为逻辑关系表达式,则结果为真时,stdout输出1,否则输出0。
    • expr的exit code:如果为逻辑关系表达式,则结果为真时,exit code为0,否则为1。

字符串表达式

  • length STRING

    • 返回STRING的长度
  • index STRING CHARSET

    • CHARSET中任意单个字符在STRING中最前面的字符位置,下标从1开始。如果在STRING中完全不存在CHARSET中的字符,则返回0。
  • substr STRING POSITION LENGTH

    • 返回STRING字符串中从POSITION开始,长度最大为LENGTH的子串。如果POSITION或LENGTH为负数,0或非数值,则返回空字符串。
  • 示例:

str="Hello World!"

echo expr length $str
# 空格会使命令产生错误,所以要加双引号
echo `expr length "$str"`  # ``不是单引号,表示执行该命令,输出12
echo `expr index "$str" aWd`  # 输出7,下标从1开始
echo `expr substr "$str" 2 3`  # 输出 ell
echo ${str:2:3}  # 提取从2开始的3个字符

整数表达式

  • expr支持普通的算术操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式。

    • + -:加减运算。两端参数会转换为整数,如果转换失败则报错。
    • * / %:乘,除,取模运算。两端参数会转换为整数,如果转换失败则报错。
    • () 可以改变优先级,但需要用反斜杠转义
  • 示例:

a=3
b=4

echo `expr $a + $b`  # 输出7
echo `expr $a - $b`  # 输出-1
echo `expr $a \* $b`  # 输出12,*需要转义
echo `expr $a / $b`  # 输出0,整除
echo `expr $a % $b` # 输出3
echo `expr \( $a + 1 \) \* \( $b + 1 \)`  # 输出20,值为(a + 1) * (b + 1)
# 先加空格,后加转义
echo `expr ($a+1)*($b+1)`
echo `expr ( $a + 1 ) * ( $b + 1 ) `
echo `expr \( $a + 1 \) \* \( $b + 1 \)`

echo $[n**m] # 求n的m次幂

逻辑关系表达式

  • |

    • 如果第一个参数非空且非0,则返回第一个参数的值,否则返回第二个参数的值,但要求第二个参数的值也是非空或非0,否则返回0。如果第一个参数是非空或非0时,不会计算第二个参数。
  • &

    • 如果两个参数都非空且非0,则返回第一个参数,否则返回0。如果第一个参为0或为空,则不会计算第二个参数。
  • < <= = == != >= >

    • 比较两端的参数,如果为true,则返回1,否则返回0。”==”是”=”的同义词。”expr”首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。
  • () 可以改变优先级,但需要用反斜杠转义

  • 示例:

a=3
b=4

echo `expr $a \> $b`  # 输出0,>需要转义
echo `expr $a '<' $b`  # 输出1,也可以将特殊字符用引号引起来
echo `expr $a '>=' $b`  # 输出0
echo `expr $a \<\= $b`  # 输出1

echo `expr 3 '<' 2` # stdout输出0,exit code为1
echo `expr 3 '>' 2` # stdout输出1,exit code为0

c=0
d=5

echo `expr $c \& $d`  # 第一个是假,直接输出0
echo `expr $a \& $b`  # 输出3
echo `expr $c \| $d`  # 输出5
echo `expr $a \| $b`  # 两个都是真,会返回第一个值,输出3

read命令

  • read命令用于从标准输入中读取单行数据。当读到文件结束符时,exit code为1,否则为0。

  • 参数说明

    • -p: 后面可以接提示信息
    • -t:后面跟秒数,定义输入字符的等待时间,超过等待时间后会自动忽略此命令
    • -t-p 的顺序不影响实际效果
  • 实例:

acs@9e0ebfcd82d7:~$ read name  # 读入name的值
acwing yxc  # 标准输入
acs@9e0ebfcd82d7:~$ echo $name  # 输出name的值
acwing yxc  #标准输出
acs@9e0ebfcd82d7:~$ read -p "Please input your name: " -t 30 name  # 读入name的值,等待时间30秒
Please input your name: acwing yxc  # 标准输入
acs@9e0ebfcd82d7:~$ echo $name  # 输出name的值
acwing yxc  # 标准输出

echo命令

概述

  • echo用于输出字符串。命令格式:
echo STRING

显示普通字符串

echo "Hello AC Terminal"
echo Hello AC Terminal  # 引号可以省略

显示转义字符

tip:[start]
单原双变
tip:[end]

echo "\"Hello AC Terminal\""  # 注意只能使用双引号,如果使用单引号,则不转义
echo \"Hello AC Terminal\"  # 也可以省略双引号

显示变量

name=yxc
echo "My name is $name"  # 输出 My name is yxc

显示换行

echo -e "Hi\n"  # -e 开启转义
echo "acwing"

# \\ \a \b \c \d \e \f \n \r \t \v 这些是要在有 - e 的时候才能起作用, 其他时候的转义是不用- e也能转义的。
man echo
help echo
  • 输出结果:
Hi

acwing

显示不换行

echo -e "Hi \c" # -e 开启转义 \c 不换行
echo "acwing"
  • 输出结果:
Hi acwing

显示结果定向至文件

echo "Hello World" > output.txt  # 将内容以覆盖的方式输出到output.txt中

原样输出字符串,不进行转义或取变量(用单引号)

name=acwing
echo '$name\"'
  • 输出结果
$name\"

显示命令的执行结果

echo `date`
  • 输出结果:
Wed Sep 1 11:45:33 CST 2021

printf命令

概述

  • printf命令用于格式化输出,类似于C/C++中的printf函数。

  • 默认不会在字符串末尾添加换行符。

  • 命令格式:

printf format-string [arguments...]

用法示例

  • 脚本内容:
printf "%10d.\n" 123  # 占10位,右对齐
printf "%-10.2f.\n" 123.123321  # 占10位,保留2位小数,左对齐
printf "My name is %s\n" "yxc"  # 格式化输出字符串
printf "%d * %d = %d\n"  2 3 `expr 2 \* 3` # 表达式的值作为参数
  • 输出结果:
       123.
123.12    .
My name is yxc
2 * 3 = 6

test命令与判断符号[]

逻辑运算符&&和||

  • && 表示与,|| 表示或

  • 二者具有短路原则:可以实现if

    • expr1 && expr2:当expr1为假时,直接忽略expr2
    • expr1 || expr2:当expr1为真时,直接忽略expr2
  • 表达式的exit code为0,表示真;为非零,表示假。(与C/C++中的定义相反)

test命令

  • 在命令行中输入man test,可以查看test命令的用法。

  • test命令用于判断文件类型,以及对变量做比较。

  • test命令用exit code返回结果,而不是使用stdout。0表示真,非0表示假。

  • 例如:

# -lt:less than(小于)
test 2 -lt 3  # 为真,返回值为0
echo $?  # 输出上个命令的返回值,输出0
acs@9e0ebfcd82d7:~$ ls  # 列出当前目录下的所有文件
homework  output.txt  test.sh  tmp
acs@9e0ebfcd82d7:~$ test -e test.sh && echo "exist" || echo "Not exist"
exist  # test.sh 文件存在
acs@9e0ebfcd82d7:~$ test -e test2.sh && echo "exist" || echo "Not exist"
Not exist  # testh2.sh 文件不存在

文件类型判断

  • 命令格式:
test -e filename  # 判断文件是否存在
测试参数 代表意义
-e 文件是否存在
-f 是否为文件
-d 是否为目录

文件权限判断

  • 命令格式:
test -r filename  # 判断文件是否可读
测试参数 代表意义
-r 文件是否可读
-w 文件是否可写
-x 文件是否可执行
-s 是否为非空文件

整数间的比较

  • 命令格式:
# 在sh中只能用于整数的比较,不能用于字符串
test $a -eq $b  # a是否等于b
测试参数 代表意义
-eq equal, a是否等于b
-ne not equal, a是否不等于b
-gt greater than, a是否大于b
-lt less than, a是否小于b
-ge greater than or equal, a是否大于等于b
-le less than or equal, a是否小于等于b

字符串比较

测试参数 代表意义
test -z STRING 判断STRING是否为空,如果为空,则返回true
test -n STRING 判断STRING是否非空,如果非空,则返回true(-n可以省略)
test str1 == str2 判断str1是否等于str2
test str1 != str2 判断str1是否不等于str2
-ge a是否大于等于b
-le a是否小于等于b

多重条件判定

  • 命令格式:
test -r filename -a -x filename
测试参数 代表意义
-a and,两条件是否同时成立
-o or,两条件是否至少一个成立
! 取反。如 test ! -x file,当file不可执行时,返回true

判断符号[]

  • []test用法几乎一模一样,更常用于if语句中。另外[[]][]的加强版,支持的特性更多。

  • 例如:

[ 2 -lt 3 ]  # 为真,返回值为0
echo $?  # 输出上个命令的返回值,输出0
acs@9e0ebfcd82d7:~$ ls  # 列出当前目录下的所有文件
homework  output.txt  test.sh  tmp
acs@9e0ebfcd82d7:~$ [ -e test.sh ] && echo "exist" || echo "Not exist"
exist  # test.sh 文件存在
acs@9e0ebfcd82d7:~$ [ -e test2.sh ] && echo "exist" || echo "Not exist"
Not exist  # testh2.sh 文件不存在
  • 注意:

    • []内的每一项都要用空格隔开
    • 中括号内的变量,最好用双引号括起来
    • 中括号内的常数,最好用单或双引号括起来
  • 例如:

name="acwing yxc"
[ $name == "acwing yxc" ]  # 错误,等价于 [ acwing yxc == "acwing yxc" ],参数太多
[ "$name" == "acwing yxc" ]  # 正确

判断语句

if…then形式

  • 类似于C/C++中的if-else语句。

单层if

  • 命令格式:
if condition
then
    语句1
    语句2
    ...
fi
  • 示例:
a=3
b=4

if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ]
then
    echo ${a}在范围内
fi
  • 输出结果:
3在范围内

单层if-else

  • 命令格式
if condition
then
    语句1
    语句2
    ...
else
    语句1
    语句2
    ...
fi
  • 示例:
a=3
b=4

if ! [ "$a" -lt "$b" ]
then
    echo ${a}不小于${b}
else
    echo ${a}小于${b}
fi
  • 输出结果:
3小于4

多层if-elif-elif-else

  • 命令格式
if condition
then
    语句1
    语句2
    ...
elif condition
then
    语句1
    语句2
    ...
elif condition
then
    语句1
    语句2
else
    语句1
    语句2
    ...
fi
  • 示例:
a=4

if [ $a -eq 1 ]
then
    echo ${a}等于1
elif [ $a -eq 2 ]
then
    echo ${a}等于2
elif [ $a -eq 3 ]
then
    echo ${a}等于3
else
    echo 其他
fi
  • 输出结果:
其他

case…esac形式

  • 类似于C/C++中的switch语句。

  • 命令格式

case $变量名称 in
    值1)
        语句1
        语句2
        ...
        ;;  # 类似于C/C++中的break
    值2)
        语句1
        语句2
        ...
        ;;
    *)  # 类似于C/C++中的default
        语句1
        语句2
        ...
        ;;
esac
  • 示例:
a=4

case $a in
    1)
        echo ${a}等于1
        ;;
    2)
        echo ${a}等于2
        ;;
    3)
        echo ${a}等于3
        ;;
    *)
        echo 其他
        ;;
esac
  • 输出结果:
其他
posted @   JiajiaMing  阅读(6)  评论(0编辑  收藏  举报
首页
随笔
博客园
我的
标签
管理
Linux_3 shell语法
发表于 2023-12-09 22:28
|
已有 6 人阅读
|
留下 0 条评论
|
全文字数 ≈ 578字
分类:
标签:

概论

shell是什么

  • shell是我们通过命令行与操作系统沟通的语言。

  • shell脚本可以直接在命令行中执行,也可以将一套逻辑组织成一个文件,方便复用。

  • AC Terminal中的命令行可以看成是一个“shell脚本在逐行执行”。

  • Linux中常见的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文件,内容如下:
SH
#! /bin/bash
echo "Hello World!"

运行方式

作为可执行文件

SH
# 作为可执行文件执行需要权限
acs@9e0ebfcd82d7:~$ ls -l test.sh # 查看权限
acs@9e0ebfcd82d7:~$ chmod +x test.sh  # 使脚本具有可执行权限
acs@9e0ebfcd82d7:~$ ./test.sh  # 当前路径下执行
Hello World!  # 脚本输出
acs@9e0ebfcd82d7:~$ /home/acs/test.sh  # 绝对路径下执行
Hello World!  # 脚本输出
acs@9e0ebfcd82d7:~$ ~/test.sh  # 家目录路径下执行
Hello World!  # 脚本输出

用解释器执行

SH
# 解释器执行不需要有可执行权限
acs@9e0ebfcd82d7:~$ bash test.sh
Hello World!  # 脚本输出

注释

单行注释

  • 每行中#之后的内容均是注释。
SH
# 这是一行注释
echo 'Hello World'  #  这也是注释

多行注释

SH
# 格式:
:<<EOF
	第一行注释
	第二行注释
	第三行注释
EOF

# 其中EOF可以换成其它任意字符串。例如:
:<<abc
	第一行注释
	第二行注释
	第三行注释
abc

:<<!
	第一行注释
	第二行注释
	第三行注释
!

变量

定义变量

  • 定义变量,不需要加$符号,例如:
SH
# 定义变量时,等号两边不能有空格
name1='hf'  # 单引号定义字符串
name2="hf"  # 双引号定义字符串
name3=hf    # 也可以不加引号,同样表示字符串

使用变量

  • 使用变量,需要加上$符号,或者${}符号。
  • 花括号是可选的,主要为了帮助解释器识别变量边界。
SH
name=hf
echo $name  # 输出yxc
echo ${name}  # 输出yxc
echo ${name}acwing  # 输出yxcacwing

只读变量

  • 使用readonly或者declare可以将变量变为只读。
SH
name=hf
readonly name
declare -r name  # 两种写法均可

name=abc  # 会报错,因为此时name只读

删除变量

  • unset可以删除变量。
SH
# 被声明为只读的变量无法被unset删除
name=hf
unset name
echo $name  # 输出空行

变量类型

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

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

SH
# 自定义变量改成环境变量:
# 默认变量是局部变量(自定义变量)
acs@9e0ebfcd82d7:~$ name=hf  # 定义变量
acs@9e0ebfcd82d7:~$ export name  # 第一种方法
acs@9e0ebfcd82d7:~$ declare -x name  # 第二种方法

# 环境变量改为自定义变量:
acs@9e0ebfcd82d7:~$ export name=hf  # 定义环境变量
acs@9e0ebfcd82d7:~$ declare +x name  # 改为自定义变量

❗注意

tmux经ctrl a + %后分屏的两个界面实际上是两个bash,在一个bash中自定义的bash变量仅可以被当前bash访问,通过bash命令开启的子进程也无法访问。export后变量变为环境变量,就可以被全局访问。

字符串

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

  • 单引号与双引号的区别:

    • 单引号中的内容会原样输出,不会执行、不会取变量;
    • 双引号中的内容可以执行、可以取变量;
SH
name=yxc  # 不用引号
echo 'hello, $name \"hh\"'  # 单引号字符串,输出 hello, $name \"hh\"
echo "hello, $name \"hh\""  # 双引号字符串,输出 hello, yxc "hh"
# 字符串中,不加引号和双引号效果相同
echo hello, $name \"hh\"  # 无引号字符串,输出 hello, yxc "hh"
  • 获取字符串长度
SH
name="yxc"
echo ${#name}  # 输出3
  • 提取子串
SH
name="hello, yxc"
echo ${name:0:5}  # 提取从0开始的5个字符

默认变量

文件参数变量

  • 在执行sh脚本时,可以向脚本传递参数。$1是第一个参数,$2是第二个参数,以此类推。特殊的,$0是文件名(包含路径)。例如:

  • 创建文件test.sh:

SH
#! /bin/bash

echo "文件名:"$0
echo "第一个参数:"$1
echo "第二个参数:"$2
echo "第三个参数:"$3
echo "第四个参数:"$4
# 如果取的是第10个输入参数的话,一定需要加上{},否则,$10是输出第一参数后再输出一个0,如下:
echo ${10}
echo ${11}
  • 然后执行该脚本:
SH
acs@9e0ebfcd82d7:~$ chmod +x test.sh
acs@9e0ebfcd82d7:~$ ./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开始

定义

  • 数组用小括号表示,元素之间用空格隔开。例如:
SH
array=(1 abc "def" yxc)
  • 也可以直接定义数组中某个元素的值:
SH
array[0]=1
array[1]=abc
array[2]="def"
array[3]=yxc

读取数组中某个元素的值

  • 格式:
SH
${array[index]} # 变量替换

❗注意

$(sdout) # 注意区分!

SH
# $(command):返回command这条命令的stdout(可嵌套)
# ${sdout}:变量替换,取变量的值

  • 例如:
SH
array=(1 abc "def" yxc)
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}

读取整个数组

  • 格式:
SH
${array[@]}  # 第一种写法
${array[*]}  # 第二种写法
  • 例如:
SH
array=(1 abc "def" yxc)

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

数组长度

  • 类似于字符串
SH
${#array[@]}  # 第一种写法
${#array[*]}  # 第二种写法
  • 例如:
SH
array=(1 abc "def" yxc)

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

表达式运算命令expr

概述

  • expr命令用于求表达式的值,格式为:
SH
expr 表达式
  • 表达式说明:
    • 用空格隔开每一项
    • 用反斜杠放在sh特定的字符前面(发现表达式运行错误时,可以试试转义)
    • 对包含空格和其他特殊字符的字符串要用引号括起来
    • expr会在stdout中输出结果。如果为逻辑关系表达式,则结果为真时,stdout输出1,否则输出0。
    • expr的exit code:如果为逻辑关系表达式,则结果为真时,exit code为0,否则为1。

字符串表达式

  • length STRING

    • 返回STRING的长度
  • index STRING CHARSET

    • CHARSET中任意单个字符在STRING中最前面的字符位置,下标从1开始。如果在STRING中完全不存在CHARSET中的字符,则返回0。
  • substr STRING POSITION LENGTH

    • 返回STRING字符串中从POSITION开始,长度最大为LENGTH的子串。如果POSITION或LENGTH为负数,0或非数值,则返回空字符串。
  • 示例:

SH
str="Hello World!"

echo expr length $str
# 空格会使命令产生错误,所以要加双引号
echo `expr length "$str"`  # ``不是单引号,表示执行该命令,输出12
echo `expr index "$str" aWd`  # 输出7,下标从1开始
echo `expr substr "$str" 2 3`  # 输出 ell
echo ${str:2:3}  # 提取从2开始的3个字符

整数表达式

  • expr支持普通的算术操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式。

    • + -:加减运算。两端参数会转换为整数,如果转换失败则报错。
    • * / %:乘,除,取模运算。两端参数会转换为整数,如果转换失败则报错。
    • () 可以改变优先级,但需要用反斜杠转义
  • 示例:

SH
a=3
b=4

echo `expr $a + $b`  # 输出7
echo `expr $a - $b`  # 输出-1
echo `expr $a \* $b`  # 输出12,*需要转义
echo `expr $a / $b`  # 输出0,整除
echo `expr $a % $b` # 输出3
echo `expr \( $a + 1 \) \* \( $b + 1 \)`  # 输出20,值为(a + 1) * (b + 1)
# 先加空格,后加转义
echo `expr ($a+1)*($b+1)`
echo `expr ( $a + 1 ) * ( $b + 1 ) `
echo `expr \( $a + 1 \) \* \( $b + 1 \)`

echo $[n**m] # 求n的m次幂

逻辑关系表达式

  • |

    • 如果第一个参数非空且非0,则返回第一个参数的值,否则返回第二个参数的值,但要求第二个参数的值也是非空或非0,否则返回0。如果第一个参数是非空或非0时,不会计算第二个参数。
  • &

    • 如果两个参数都非空且非0,则返回第一个参数,否则返回0。如果第一个参为0或为空,则不会计算第二个参数。
  • < <= = == != >= >

    • 比较两端的参数,如果为true,则返回1,否则返回0。”==”是”=”的同义词。”expr”首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。
  • () 可以改变优先级,但需要用反斜杠转义

  • 示例:

SH
a=3
b=4

echo `expr $a \> $b`  # 输出0,>需要转义
echo `expr $a '<' $b`  # 输出1,也可以将特殊字符用引号引起来
echo `expr $a '>=' $b`  # 输出0
echo `expr $a \<\= $b`  # 输出1

echo `expr 3 '<' 2` # stdout输出0,exit code为1
echo `expr 3 '>' 2` # stdout输出1,exit code为0

c=0
d=5

echo `expr $c \& $d`  # 第一个是假,直接输出0
echo `expr $a \& $b`  # 输出3
echo `expr $c \| $d`  # 输出5
echo `expr $a \| $b`  # 两个都是真,会返回第一个值,输出3

read命令

  • read命令用于从标准输入中读取单行数据。当读到文件结束符时,exit code为1,否则为0。

  • 参数说明

    • -p: 后面可以接提示信息
    • -t:后面跟秒数,定义输入字符的等待时间,超过等待时间后会自动忽略此命令
    • -t-p 的顺序不影响实际效果
  • 实例:

SH
acs@9e0ebfcd82d7:~$ read name  # 读入name的值
acwing yxc  # 标准输入
acs@9e0ebfcd82d7:~$ echo $name  # 输出name的值
acwing yxc  #标准输出
acs@9e0ebfcd82d7:~$ read -p "Please input your name: " -t 30 name  # 读入name的值,等待时间30秒
Please input your name: acwing yxc  # 标准输入
acs@9e0ebfcd82d7:~$ echo $name  # 输出name的值
acwing yxc  # 标准输出

echo命令

概述

  • echo用于输出字符串。命令格式:
SH
echo STRING

显示普通字符串

SH
echo "Hello AC Terminal"
echo Hello AC Terminal  # 引号可以省略

显示转义字符

💡提示

单原双变

SH
echo "\"Hello AC Terminal\""  # 注意只能使用双引号,如果使用单引号,则不转义
echo \"Hello AC Terminal\"  # 也可以省略双引号

显示变量

SH
name=yxc
echo "My name is $name"  # 输出 My name is yxc

显示换行

SH
echo -e "Hi\n"  # -e 开启转义
echo "acwing"

# \\ \a \b \c \d \e \f \n \r \t \v 这些是要在有 - e 的时候才能起作用, 其他时候的转义是不用- e也能转义的。
man echo
help echo
  • 输出结果:
SH
Hi

acwing

显示不换行

SH
echo -e "Hi \c" # -e 开启转义 \c 不换行
echo "acwing"
  • 输出结果:
SH
Hi acwing

显示结果定向至文件

SH
echo "Hello World" > output.txt  # 将内容以覆盖的方式输出到output.txt中

原样输出字符串,不进行转义或取变量(用单引号)

SH
name=acwing
echo '$name\"'
  • 输出结果
SH
$name\"

显示命令的执行结果

SH
echo `date`
  • 输出结果:
SH
Wed Sep 1 11:45:33 CST 2021

printf命令

概述

  • printf命令用于格式化输出,类似于C/C++中的printf函数。

  • 默认不会在字符串末尾添加换行符。

  • 命令格式:

SH
printf format-string [arguments...]

用法示例

  • 脚本内容:
SH
printf "%10d.\n" 123  # 占10位,右对齐
printf "%-10.2f.\n" 123.123321  # 占10位,保留2位小数,左对齐
printf "My name is %s\n" "yxc"  # 格式化输出字符串
printf "%d * %d = %d\n"  2 3 `expr 2 \* 3` # 表达式的值作为参数
  • 输出结果:
SH
       123.
123.12    .
My name is yxc
2 * 3 = 6

test命令与判断符号[]

逻辑运算符&&和||

  • && 表示与,|| 表示或

  • 二者具有短路原则:可以实现if

    • expr1 && expr2:当expr1为假时,直接忽略expr2
    • expr1 || expr2:当expr1为真时,直接忽略expr2
  • 表达式的exit code为0,表示真;为非零,表示假。(与C/C++中的定义相反)

test命令

  • 在命令行中输入man test,可以查看test命令的用法。

  • test命令用于判断文件类型,以及对变量做比较。

  • test命令用exit code返回结果,而不是使用stdout。0表示真,非0表示假。

  • 例如:

SH
# -lt:less than(小于)
test 2 -lt 3  # 为真,返回值为0
echo $?  # 输出上个命令的返回值,输出0
SH
acs@9e0ebfcd82d7:~$ ls  # 列出当前目录下的所有文件
homework  output.txt  test.sh  tmp
acs@9e0ebfcd82d7:~$ test -e test.sh && echo "exist" || echo "Not exist"
exist  # test.sh 文件存在
acs@9e0ebfcd82d7:~$ test -e test2.sh && echo "exist" || echo "Not exist"
Not exist  # testh2.sh 文件不存在

文件类型判断

  • 命令格式:
SH
test -e filename  # 判断文件是否存在
测试参数 代表意义
-e 文件是否存在
-f 是否为文件
-d 是否为目录

文件权限判断

  • 命令格式:
SH
test -r filename  # 判断文件是否可读
测试参数 代表意义
-r 文件是否可读
-w 文件是否可写
-x 文件是否可执行
-s 是否为非空文件

整数间的比较

  • 命令格式:
SH
# 在sh中只能用于整数的比较,不能用于字符串
test $a -eq $b  # a是否等于b
测试参数 代表意义
-eq equal, a是否等于b
-ne not equal, a是否不等于b
-gt greater than, a是否大于b
-lt less than, a是否小于b
-ge greater than or equal, a是否大于等于b
-le less than or equal, a是否小于等于b

字符串比较

测试参数 代表意义
test -z STRING 判断STRING是否为空,如果为空,则返回true
test -n STRING 判断STRING是否非空,如果非空,则返回true(-n可以省略)
test str1 == str2 判断str1是否等于str2
test str1 != str2 判断str1是否不等于str2
-ge a是否大于等于b
-le a是否小于等于b

多重条件判定

  • 命令格式:
SH
test -r filename -a -x filename
测试参数 代表意义
-a and,两条件是否同时成立
-o or,两条件是否至少一个成立
! 取反。如 test ! -x file,当file不可执行时,返回true

判断符号[]

  • []test用法几乎一模一样,更常用于if语句中。另外[[]][]的加强版,支持的特性更多。

  • 例如:

SH
[ 2 -lt 3 ]  # 为真,返回值为0
echo $?  # 输出上个命令的返回值,输出0
SH
acs@9e0ebfcd82d7:~$ ls  # 列出当前目录下的所有文件
homework  output.txt  test.sh  tmp
acs@9e0ebfcd82d7:~$ [ -e test.sh ] && echo "exist" || echo "Not exist"
exist  # test.sh 文件存在
acs@9e0ebfcd82d7:~$ [ -e test2.sh ] && echo "exist" || echo "Not exist"
Not exist  # testh2.sh 文件不存在
  • 注意:

    • []内的每一项都要用空格隔开
    • 中括号内的变量,最好用双引号括起来
    • 中括号内的常数,最好用单或双引号括起来
  • 例如:

SH
name="acwing yxc"
[ $name == "acwing yxc" ]  # 错误,等价于 [ acwing yxc == "acwing yxc" ],参数太多
[ "$name" == "acwing yxc" ]  # 正确

判断语句

if…then形式

  • 类似于C/C++中的if-else语句。

单层if

  • 命令格式:
SH
if condition
then
    语句1
    语句2
    ...
fi
  • 示例:
SH
a=3
b=4

if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ]
then
    echo ${a}在范围内
fi
  • 输出结果:
SH
3在范围内

单层if-else

  • 命令格式
SH
if condition
then
    语句1
    语句2
    ...
else
    语句1
    语句2
    ...
fi
  • 示例:
SH
a=3
b=4

if ! [ "$a" -lt "$b" ]
then
    echo ${a}不小于${b}
else
    echo ${a}小于${b}
fi
  • 输出结果:
SH
3小于4

多层if-elif-elif-else

  • 命令格式
SH
if condition
then
    语句1
    语句2
    ...
elif condition
then
    语句1
    语句2
    ...
elif condition
then
    语句1
    语句2
else
    语句1
    语句2
    ...
fi
  • 示例:
SH
a=4

if [ $a -eq 1 ]
then
    echo ${a}等于1
elif [ $a -eq 2 ]
then
    echo ${a}等于2
elif [ $a -eq 3 ]
then
    echo ${a}等于3
else
    echo 其他
fi
  • 输出结果:
SH
其他

case…esac形式

  • 类似于C/C++中的switch语句。

  • 命令格式

SH
case $变量名称 in
    值1)
        语句1
        语句2
        ...
        ;;  # 类似于C/C++中的break
    值2)
        语句1
        语句2
        ...
        ;;
    *)  # 类似于C/C++中的default
        语句1
        语句2
        ...
        ;;
esac
  • 示例:
SH
a=4

case $a in
    1)
        echo ${a}等于1
        ;;
    2)
        echo ${a}等于2
        ;;
    3)
        echo ${a}等于3
        ;;
    *)
        echo 其他
        ;;
esac
  • 输出结果:
SH
其他
作者:jia-ming
出处: https://www.cnblogs.com/jia-ming/#/p/17890814
版权:本作品采用「 署名-非商业性使用-相同方式共享 4.0 国际 」许可协议进行许可。
文章目录
概论
shell是什么
脚本示例
运行方式
作为可执行文件
用解释器执行
注释
单行注释
多行注释
变量
定义变量
使用变量
只读变量
删除变量
变量类型
字符串
默认变量
文件参数变量
数组
定义
读取数组中某个元素的值
读取整个数组
数组长度
表达式运算命令expr
概述
字符串表达式
整数表达式
逻辑关系表达式
read命令
echo命令
概述
显示普通字符串
显示转义字符
显示变量
显示换行
显示不换行
显示结果定向至文件
原样输出字符串,不进行转义或取变量(用单引号)
显示命令的执行结果
printf命令
概述
用法示例
test命令与判断符号[]
逻辑运算符&&和||
test命令
文件类型判断
文件权限判断
整数间的比较
字符串比较
多重条件判定
判断符号[]
判断语句
if…then形式
单层if
单层if-else
多层if-elif-elif-else
case…esac形式
点击右上角即可分享
微信分享提示