Linux之Shell学习笔记

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux之Shell学习笔记相关的知识,希望对你有一定的参考价值。

注:本学习笔记来源于视频:尚硅谷-3天搞定Linux,1天搞定Shell(2022版)。光看这一个视频对于 Linux 和 Shell 了解还是有些不够,可以结合视频 黑马-2019全新Shell脚本从入门到精通教程,该视频介绍了更多命令的使用。两个视频结合起来学习,能加深对 Shell 脚本的掌握。

第 1章 Shell 概述

Shell 是一个命令行解释器,它接收应用程序或用户命令(如 ls 等命令),然后调用操作系统内核。同时 Shell 也是一个功能强大的脚本语言。

  • 可以通过 cat /etc/shells 查看当前系统提供的 Shell 解析器:

  • bashsh 的关系:实际上 sh 就是 bash 的软链接。

  • 当前系统默认的 Shell 解析器可以通过 echo $SHELL 命令查看:

第 2 章 Shell 脚本入门

2.1 脚本格式

脚本以 #!/bin/bash 开头,指定解析器。

2.2 第一个 Shell 脚本:hello.sh

使用 vim hello.sh 创建第一个脚本,然后输入如下内容:

#!/bin/bash

echo "hello world!"

2.3 脚本的常用执行方式

2.3.1 第一种执行方式

采用 bash 脚本路径sh 脚本路径 的方式执行脚本。其中 脚本路径 可以是脚本的相对路径或绝对路径。该种方式不需要赋予脚本执行权限。

# 语法
sh 脚本相对路径
sh 脚本绝对路径
bash 脚本相对路径
bash 脚本绝对路径
# 示例
sh ./hello.sh
sh /root/hello.sh
bash ./hello.sh
bash /root/hello.sh

2.3.2 第二种执行方式

可以采用在命令行种输入脚本的绝对路径或相对路径执行脚本,但前提是必须具有可执行权限 +x

所以首先要为脚本文件(如 hello.sh)添加可执行权限:

# 语法
chmod +x 脚本文件名
# 示例
chmod +x hello.sh

接着输入脚本的绝对路径或相对路径来执行脚本:

# 语法
脚本的相对路径
脚本的绝对路径
# 示例
./hello.sh
/root/hello.sh

注意:第一种执行方法,本质是 bash 解析器帮你执行脚本,所以脚本本身不需要执行权限。第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。

第三种执行方式

在脚本的路径前加上 . 或者 source 来执行脚本:

# 语法
. 脚本路径
# 或
source 脚本路径

前两种方式都是在当前 shell 中打开一个子 shell 来执行脚本内容,当脚本内容结束,则子 shell 关闭,回到父 shell 中。第三种,也就是使用在脚本路径前加 . 或者 source 的方式,可以使脚本内容在当前 shell 里执行,而无需打开子 shell。这也是为什么我们每次要修改完 /etc/profile 文件以后,需要 source 一下的原因。

开子 shell 与不开子 shell 的区别就在于,环境变量的继承关系,如在子 shell 中设置的当前变量,父 shell 是不可见的。

在当前命令行窗口输入 bash 即可进入一个子 shell,使用 exit 退出子 shell 回到父 shell。

第 3 章 变量

3.1 系统预定义变量

常用的系统变量有:$HOME$PWD$SHELL$USER 等。可以通过 echo $系统变量名 进行查看:


如果要查看当前 Shell 的所有变量(包括普通变量和系统变量),可以通过 set 命令查看:

3.2 自定义变量

3.2.1 声明变量

自定义变量的语法如下:

# 语法,注意等号两侧不能有空格
变量名=变量值
# 示例
path="/root/"
count=3

还有一种静态变量,即不能 unset 的变量。语法如下:

# 语法,声明静态变量
readonly 静态变量名=变量值
# 示例
readonly a=123

3.2.2 撤销变量

因为已经创建的变量不能随便删除,只能撤销,所以撤销变量的语法如下:

# 语法
unset 变量名
# 示例
unset path
unset count

3.2.3 调用变量

如果要获取变量的值,语法如下:

# 语法,即在变量名的前面加上美元符号 $ 即可访问到该变量的值
echo $变量名
# 示例
echo $USER
echo $info

3.2.4 变量定义规则

变量定义需要遵循一定的规则,如下:

  • (1)变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
  • (2)等号两侧不能有空格
  • (3)在 bash 中,变量默认类型都是字符串类型,无法直接进行数值运算。
  • (4)变量的值如果有空格,需要使用双引号或单引号括起来。建议如果是文件路径则用双引号括起来。

3.2.5 变量实例

# 定义变量 A 并进行访问
A=123
echo $A

# 给变量 A 重新赋值
A=456
echo $A

# 撤销变量 A
unset A
echo $A

# 声明静态变量 B=3,不能 unset
readonly B=3
echo $B
B=9 # 不能
unset B # 不能

# 在 bash 中,变量默认类型都是字符串类型,无法直接进行数值运算
C=1+2
echo $C # 结果为 1+2

# 变量的值如果有空格,需要用双引号或单引号括起来
D="hello world"
echo $D

# 可以将变量提升为全局环境变量,可以供其他 shell 程序使用。即在任意脚本文件中都可以直接使用这个全局变量
export 变量名

3.3 特殊变量

3.3.1 $n

基本语法:

$n

作用:n 为数字,$0 代表该脚本名称,$1-$9 代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如$10

示例:test.sh

#!/bin/bash

echo "==================$n=================="
# 获取脚本名
echo $0
# 获取传入的第一个参数
echo $1
# 获取传入的第二个参数
echo $2

3.3.2 $#

基本语法:

$#

作用:获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及加强脚本的健壮性。

示例:

#!/bin/bash

echo '==================$n=================='
# 获取脚本名
echo $0
# 获取传入的第一个参数
echo $1
# 获取传入的第二个参数
echo $2

echo '==================$#=================='
# 获取传入的参数个数
echo $#

3.3.3 $*$@

语法如下:

# 这个变量代表命令行中所有的参数,$* 把所有的参数看成一个整体
$*
# 这个变量也代表命令行中所有的参数,不过 $@ 把每个参数区分对待
$@

示例:

#!/bin/bash

echo '==================$n=================='
# 获取脚本名
echo $0
# 获取传入的第一个参数
echo $1
# 获取传入的第二个参数
echo $2

echo '==================$#=================='
# 获取传入的参数个数
echo $#

echo '==================$*=================='
for param1 in "$*"; do
	echo $param1
done

echo '==================$@=================='
for param2 in "$@"; do
	echo $param2
done

$?

语法如下:

$?

作用:最后一次执行的命令的返回状态。如果这个变量的值为 0,证明上一个命令正确执行;如果这个变量的值为非 0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。

示例:

# 例如,输入date命令,然后查看执行返回的状态
date
echo $?

第 4 章 运算符

所谓的运算符指的是:()+-*/% 等运算符。

在 Linux 系统中如果要进行数学运算,是不能直接运算的,需要使用命令或者遵循如下格式:

# 语法
$((运算式))
#或
$[运算式]

# 示例
result=$(((2+3)*5))
echo $result
result=$[(2+3)*5]
echo $result

第 5 章 条件判断

5.1 基本语法

在 Shell 中进行条件判断,有如下语法(通常使用第二种方式):

# 语法
# 第一种方式
test 条件表达式
# 第二种方式,注意条件表达式前后必须要有空格。条件表达式非空即为 true。如 [ hello ] 返回 true,[ ] 返回 false。
[ 条件表达式 ]

5.2 常用判断条件

5.2.1 比较两个整数

如果要比较两个整数,是不能使用 >= 等符号的,需要使用如下判断:

符号说明
-eq等于(equal)
-ne不等于(not equal)
-lt小于(less than)
-le小于等于(less equal)
-gt大于(greater than)
-ge大于等于(greater than)

例如,比较 23 是否大于等于20:

5.2.2 按照文件权限判断

如果要判断文件,则判断如下:

符号说明
-e 文件路径如果文件存在则为真
-r 文件路径如果文件存在且可读则为真
-w 文件路径如果文件存在且可写则为真
-x 文件路径如果文件存在且可执行则为真
-s 文件路径如果文件存在且至少有一个字符则为真
-d 文件路径如果文件存在且为目录则为真
-f 文件路径如果文件存在且为普通文件则为真
-c 文件路径如果文件存在且为字符设备则为真
-b 文件路径如果文件存在且为块设备则为真

例如,判断 test.txt 文件是否是普通文件:

5.2.3 字符串比较

在 Shell 脚本中字符串的比较不能用 -eq,而是需要使用如下的格式:

符号说明
str1 = str2两个字符串相等则为真
str1 != str2两个字符串不相等则为真
-z str如果字符串 str 的长度为零则为零
-n str如果字符串 str 的长度不为零则为真

例如,判断字符串 "abc""abc" 是否相等:

5.3 多条件判断

如果要使用多条件判断,类似于三元表达式,语法如下:

# 语法
[ 条件表达式 ] && 条件成立执行 || 条件不成立执行
# 示例
[ hello ] && echo OK || echo notOK #OK
[ ] && echo OK || echo notOK #notOK

注:

  • && 表示前一条命令执行成功时,才执行后一条命令。
  • || 表示上一条命令执行失败后,才执行下一条命令。

除了上述的类似于三元表达式的语法之外,还提供了“与”、“或”、“非”的语法:

# 与(有两种语法),表示多个条件都满足时才成立
[ 条件表达式1 ] && [ 条件表达式2 ]
[ 条件表达式1 -a 条件表达式2 ]

# 或(也有两种语法),表示只要有一个条件满足就成立
[ 条件表达式1 ] || [ 条件表达式2 ]
[ 条件表达式1 -o 条件表达式2 ]

# 非,表示取反
! 条件表达式

第 6 章 流程控制

6.1 if 判断

  • 单分支
if [ 条件判断式 ]; then
		条件体
fi

# 或

if [ 条件判断式 ]
then
	条件体
fi
  • 多分支
if [ 条件判断式 ]; then
		条件体
elif [ 条件判断式 ]; then
		条件体
else
		条件体
fi				

示例如下:

#!/bin/bash

a=2
b=3

if [ $a -gt $b ]; then
    echo "a>b"
elif [ $a -lt $b ]; then
    echo "a<b"
else
    echo "a=b"
fi

注:

  • [ 条件判断式 ] 中括号和条件判断式之间必须要有空格。
    if 后面要隔着空格。
    ; 表示一行上执行多条命令。

6.2 case 语句

基本语法如下:

case $变量名 in
"值 1")
		如果变量的值等于值 1,则执行程序 1
		;;
"值 2")
		如果变量的值等于值 2,则执行程序 2
		;;
…省略其他分支…
*)
		如果变量的值都不是以上的值,则执行此程序
		;;
esac

例如:

#!/bin/bash

name="root"

case $name in
"zhangsan")
    echo "zhangsan"
    ;;
"root")
    echo "root"
    ;;
*)
    echo "other user"
    ;;
esac

注:

  • case 行尾必须为单词 in,每个模式匹配必须以右括号 ) 结束。
  • 待匹配的内容可以是字符、字符串、数字等。
  • 双分号 ;; 表示命令序列结束,相当于 Java 中的 break
  • 最后的 *) 表示默认,相当于 Java 中的 default

6.3 for 循环

基本语法如下:

for (( 循环变量;循环控制条件;循环变量变化 ))
do
		循环体
done

例如:从 1 加 到 100 的总和

#!/bin/bash

sum=0
for (( i=0;i<=100;i++ ))
do
    sum=$(($sum+$i))
done
echo "1+2+...+100=$sum"

除了上面的 for 循环之外,还有一类 for...in 循环,通常用来循环读取文件所有行。基本语法如下:

for 变量 in 值1 值2 值3 ...
do
		循环体
done

示例如下:

#!/bin/bash

for i in zhangsan lisi root wangwu
do
    echo "the user is $i"
done

注:$*$@ 都表示传递给函数或者脚本的所有参数,但是当它们不被双引号包含时(即 $*$@ ),都以 $1$2、……、$n 的形式输出所有参数;当它们被双引号包含时(即 "$*""$@" ),其中 "$*" 会将所有的参数当作一个整体,以 "$1 $2 ... $n" 的形式输出所有参数,而 "$@" 会将各个参数都分开,以 "$1""$2"、……、"$n" 的形式输出所有参数。

6.4 while 循环

基本语法如下:

while [ 条件判断式 ]
do
		循环体
done

例如:从 1 加 到 100 的总和

#!/bin/bash

i=1
sum=0

while [ $i -le 100 ]
do
    sum=$(($sum+$i))
    i=$(($i+1))
done
echo "1+2+...+100=$sum"

第 7 章 读取控制台输入

其实就是读取用户输入的信息,需要用到 read 命令。该命令的使用可参考:Linux命令之获取用户键盘输入read

第 8 章 函数

8.1 系统函数

主要将了两个命令的使用:

8.2 自定义函数

基本语法如下:

# 定义函数
[function] 函数名[()]

		函数体;
		[return 整数;]


# 调用函数
函数名 参数1 参数2 ...

示例如下:

#!/bin/bash

# 定义函数:计算两数之和
function sum()

    result=0
    result=$(($1+$2))
    echo "$result"


# 调用函数
read -p "请输入第一个整数:" n1
read -p "请输入第二个整数:" n2
sum $n1 $n2

注意事项:

  • 必须在调用函数地方之前,先声明函数,shell 脚本是逐行运行。不会像其它语言一
    样先编译。
  • 函数返回值,只能通过 $? c系统变量获得,可以显示加 return 整数 返回,如果不加,将
    以最后一条命令运行结果,作为返回值。return 后跟数值范围只能是 0~255
  • 如果要获取传递给函数的参数,可以通过 $1$2 这样的语法,即跟获取传递给脚本的参数一样的语法来获得。
  • 如果要获取脚本的绝对路径,可以使用这样的命令:$(cd $(dirname $0); pwd)
  • 如果想要获取返回的是非数值或大于 255 的整数,那么可以使用 echo 命令输出返回结果,然后在函数外用命令替换的方式 $(函数名 参数1 参数2 ...) 获取到函数的执行结果。

第 9 章 正则表达式入门

正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。在 Linux 中,grepsedawk 等文本处理工具都支持通过正则表达式进行模式匹配。

注:如果已经学会了正则表达式那么直接学 grepsedawk 命令中关于正则表达式中的应用即可。如果没有学会正则表达式那么可以先了解基础的正则表达式。关于正则表达式的学习可参考:正则表达式学习笔记,不必先完全学会正则表达,学会一些常用的用法就可以灵活使用在 Linux 命令上了。

第 10 章 文本处理工具

本章讲了常用命令:

注:除此之外,还有 sed 命令,也是常用的文本处理工具。

以上是关于Linux之Shell学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

Linux之Shell学习笔记

linux shell脚本学习

Linux学习笔记之shell编程基础

Linux学习笔记:bash特性之多命令执行,shell脚本

2018-4-17 Linux学习笔记

2018-1-10 Linux学习笔记