Linux–shell学习笔记(上)

概论

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

**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**文件,内 c容如下:

#! /bin/bash

echo "Hello World!"

运行方式

作为可执行文件

chmod +x test.sh # 使脚本具有可执行权限

./test.sh # 当前路径下执行

Hello World! # 脚本输出

/home/acs/test.sh # 绝对路径下执行

Hello World! # 脚本输出

~/test.sh # 家目录路径下执行

Hello World! # 脚本输出

用解释器执行

bash test.sh

Hello World! # 脚本输出

注释

单行注释

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

# 这是一行注释

echo "Hello World!" # 这也是注释

多行注释

格式:

:<<EOF

注释1

注释2

注释3

EOF

其中**EOF**可以替换成其它任意字符串 例如:

:<<abc

注释4

注释5

注释6

abc

:<<!

注释7

注释8

注释9

!

变量

定义变量

定义变量,不需要加**$**符号, 例如:

name1='xhl' # 单引号定义字符串

name2="xhl" # 双引号定义字符串

name3=xhl # 也可以不加引号, 同样表示字符串

使用变量

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

name=xhl

echo $name # 输出 xhl

echo ${name} # 输出 xhl


只读变量

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

name=xhl

readonly name

declare -r name # 两种写法均可

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

删除变量

**unset**可以删除变量

name=xhl

unset name

echo $name # 输出空行

变量类型

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

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

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

name=xhl # 定义自定义变量

export name # 第一种方法改环境变量

declare -x name # 第二种方法改环境变量

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

export name=xhl # 定义环境变量

declare +x name # 改为自定义变量

目前**tmux中就是一个bash**

name=xhl# 定义自定义变量

export name # 将自定变量修改为环境变量
# 或者是 declare -x name

bash # 进入一个新的子进程

echo $name # 输出 xhl

exit # 退出当前子进程

declare +x name # 将环境变量修改为自定义变量

bash # 进入一个新的子进程

echo $name # 输出 空行

exit # 退出当前子进程

字符串

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

单引号和双引号的区别:

单引号总的内容会原样输出,不会执行、不会取变量;

双引号中的内容可以用执行、可以取变量;

name=xhl # 不用引号

echo 'hello, $name \"hh\"' # 单引号字符串,输出 hello, $name \"hh\"

echo "hello, $name \"hh\"" # 双引号字符串, 输出 hello, xhl "hh"

获取字符串长度

name="xhl"

echo ${#name} # 输出 3

提取子串

name="hello, xhl"

echo ${name:0:5} # 提取从 0 开始的 5 个字符

默认变量

文件参数变量

在执行**shell**脚本时,可以向脚本传递参数

**$1第一个参数,$2**是第二个参数,以此类推

特殊的**$0**是文件名(包含路径)ㅤㅤ例如:

创建文件**test.sh**

#! /bin/bash

echo "文件名:$0"

echo "第一个参数:$1"

echo "第二个参数:$2"

echo "第三个参数:$3"

echo "第四个参数:$4"

echo $#

echo $*

echo $@

echo $$

echo $?

echo $(ls)

echo `ls`

然后执行该脚本:

chmod +x [test.sh](http://test.sh)

./test.sh 1 2 3 4

文件名:./test.sh

第一个参数:1

第二个参数:2

第三个参数:3

第四个参数:4

4

1 2 3 4

1 2 3 4

1582

0

homework [test.sh](http://test.sh)

homework [test.sh](http://test.sh)

其他参数相关变量



数组

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

数组下标从0开始


定义

数组用小括号表示,元素之间用空格隔开。例如:

array=(1 abc "def" xhl)

也可以直接定义数组中某个元素的值:

array[0]=1

array[1]=abc

array[2]="def"

array[3]=xhl

读取数组中某个元素的值

格式:

${array[index]}

例如:

array=(1 abc "def"  xhl)

echo ${array[0]}

echo ${array[1]}

echo ${array[2]}

echo ${array[3]}

读取整个数组

格式:

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

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

例如:

array=(1 abc "def" xhl)

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

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

数组长度

类似于字符串

只会计算被赋值了的下标

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

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

例如:

array=(1 abc "def" xhl)

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

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

expr 命令

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

expr 表达式


表达式说明

●ㅤ用空格隔开每一项

●ㅤ**用反斜杠放在shell**特定的字符前面(发现表达式运行错误时,可以试试转义)

●ㅤ对包含空格和其他特殊字符的字符串要用引号括起来

●ㅤ**expr会在stdout中输出结果。如果为逻辑关系表达式,则结果为真,stdout为1,否则为0**

●ㅤ**exprexit code:如果为逻辑关系表达式,则结果为真,exit code为0,否则为1**


字符串表达式

●ㅤ**length String 返回String的长度**

●ㅤ**index String CharSet**

ㅤㅤ**CharSet中任意单个字符在String中最前面的字符位置,下标从1开始**

ㅤㅤ**如果在String中完全不存在CharSet**中的字符,则返回0

●ㅤ**substr String Position length**

ㅤㅤ**返回String字符串中从Position开始,长度最大为length**的子串

ㅤㅤ**如果Positionlength**为负数,0或非数值,则返回空字符串

示例:

str="Hello World!"

echo $(expr length "$str") # 输出12

echo $(expr index "$str" aWd) # 输出7,下标从1开始

echo $(expr substr "$str" 2 3) # 输出 ell

echo `expr length "$str"`  # ``不是单引号,表示执行该命令,输出12

echo `expr index "$str" aWd`  # 输出7,下标从1开始

echo `expr substr "$str" 2 3`  # 输出 ell

整数表达式

**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)

逻辑表达式

●ㅤ**|:**

ㅤㅤ如果第一个参数非空且非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

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:后面跟秒数,定义输入字符的等待时间,超出等待时间后会自动忽略此命令**

实例:

read name # 读入 name 的值

xhl # 标准输入

echo $name # 输出 name 的值

xhl # 标准输出

read -p "Please input your name:" -t 30 name # 读入 name 的值,等待时间30秒

Please input your name:xhl # 标准输入

echo $name # 输出 name 的值

xhl # 标准输出

echo 命令

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

echo String


显示普通字符串

echo "Hello World"

echo Hello World # 引号可以省略

显示转义字符

echo "\"Hello World\""  # 注意只能使用双引号,如果使用单引号,则不转义

echo \"Hello World\"  # 也可以省略双引号

显示变量

name=xhl

echo "My name is $name"  # 输出 My name is xhl

显示换行

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

echo "xhl"

# 输出结果:

Hi

xhl


显示不换行

echo -e "Hi \c" # -e 开启转移 \c 不换行

echo "xhl"

# 输出结果:

Hi xhl


显示结果定向至文件

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

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

name=xhl

echo '$name\"'

# 输出结果:

$name\"

显示命令执行结果

echo `date`

# 输出结果:

Mon Dec 20 17:51:36 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" "xhl"  # 格式化输出字符串

printf "%d * %d = %d\n"  2 3 `expr 2 '*' 3` # 表达式的值作为参数

输出结果:

123.

123.12    .

My name is xhl

2 * 3 = 6

test 命令 与 判断符号 []

逻辑运算符&&和||

●ㅤ**&&表示与,||表示或**

●ㅤ二者具有短路原则:

ㅤㅤ**expr1 && expr2:当expr1为假时,直接忽略expr2**

ㅤㅤ**expr1 || expr2:当expr1为真时,直接忽略expr2**

●ㅤ**表达式的exit code为0,表示真;为非零,表示假。(与C/C++**中的定义相反)


test 命令

在命令行中输入**help test,可以查看test**命令的用法

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

test命令用exit code返回结果,而不是使用stdout

0表示真,非0表示假

例如:

test 2 -lt 3 # 为真, 返回值为0

echo $? # 输出上个命令的返回值,输出0

ls  # 列出当前目录下的所有文件

homework  output.txt  test.sh  tmp

test -e test.sh && echo "exist" || echo "Not exist"

exist  # test.sh 文件存在

test -e test2.sh && echo "exist" || echo "Not exist"

Not exist  # testh2.sh文件不存在

文件类型判断

命令格式:

test -e filename # 判断文件是否存在


文件权限判断

命令格式:

test -r filename # 判断文件是否可读


整数间的比较

命令格式:

test $a -eq $b # a是否等于b


字符串比较


多重条件判定

命令格式:

test -r filename -a -x filename


判断符号[]

**[]test用法几乎一模一样,更常用于if**语句中

另外**[[]][]**的加强版,支持的特性更多

例如:

[ 2 -lt 3 ]  # 为真,返回值为0

echo $?  # 输出上个命令的返回值,输出0

ls  # 列出当前目录下的所有文件

homework  output.txt  test.sh  tmp

[ -e test.sh ] && echo "exist" || echo "Not exist"

exist  # test.sh 文件存在

[ -e test2.sh ] && echo "exist" || echo "Not exist"

Not exist  # test2.sh 文件不存在

注意:

●ㅤ**[]内的每一项都要用空格隔开**

●ㅤ中括号内的变量,最好用双引号括起来

●ㅤ中括号内的常数,最好用单或双引号括起来

例如:

name="xhl"

[ $name == "xhl" ] # 错误

[ "$name" == "xhl" ] # 正确

06-11 13:42