Shell学习笔记
只针对菜鸟教程学习,后续再随着使用完善补充
shell环境:
Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
Shell常见种类有:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash) -- 本文记录的是Bash的学习笔记
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
在线编辑器:https://www.runoob.com/try/runcode.php?filename=helloworld&type=bash
编写及运行
- 第一行代码需要告诉系统这个脚本需要什么解释器来执行
#! /bin/bash
echo "hello world"
- 运行,以vscode运行test.sh为例(保证电脑里有git)
shell变量
变量命名
变量名的命名须遵循如下规则:
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
变量名和等号之间不能有空格
以下语句可以将文件xx下目录的文件名循环出来
for file in `ls /etc`
或
for file in $(ls /etc)
例如想打印文件dnk下的所有文件名:
for file in `ls ./dnk`;do
echo ${file}
done
使用变量
使用一个定义过的变量,只要在变量名前面加美元符号即可,如:
your_name="xiaohan"
echo $your_name
echo ${your_name}
花括号{}加不加都可以,但是不加的时候可能会出现和关键字冲突的情况,推荐写代码时加上花括号。
for skill in xian nv; do
echo "I am good at ${skill}Script"
done
以上述代码为例,上边展示的是skill没加花括号的结果,解释器就会把$skillScript当成一个变量(其值为空),下方的结果则是我们期待的运行结果。
只读变量
- 已定义的变量,可以被重新定义,如:
name="hhh"
echo ${name}
name="www"
echo ${name}
第二次赋值的时候不能写$your_name="alibaba",使用变量的时候才加美元符($)。
- 使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
my_name="xxn"
readonly my_name
my_name="dsz"
上面的例子尝试更改只读变量,结果报错:
./test.sh: line 15: my_name: readonly variable
删除变量
使用unset可以删除变量,但是只读变量不可以删除
my_name="hhh"
unset my_name
Shell字符串
定义字符串
字符串可以用单引号,也可以用双引号,也可以不用引号。当字符串有空格时,必须用引号
- 单引号
str='this is a string'
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
- 双引号
- 双引号里可以有变量
- 双引号里可以出现转义字符
- 双引号里可以直接打印出单引号,如果想打印双引号需要用转义符
my_name="xxn"
str1="hello, I know you are "${my_name}""
str2="hello, I know you are '${my_name}'"
str3="hello, I know you are ${my_name}"
str4="hello, I know you are "${my_name}""
echo "str1:${str1}"
echo "str2:${str2}"
echo "str3:${str3}"
echo "str4:${str4}"
代码运行结果为
str1:hello, I know you are "xxn"
str2:hello, I know you are 'xxn'
str3:hello, I know you are xxn
str4:hello, I know you are xxn
拼接字符串
- 使用单引号拼接
str='不错'
pinjie1='今天天气'${str}''
pinjie2='今天天气${str}'
pinjie3='今天天气"${str}"'
结果为
今天天气不错
今天天气${str}
今天天气"${str}"
- 使用双引号拼接
pinjie4="今天天气'${str}'"
pinjie5="今天天气${str}"
pinjie6="今天天气"${str}""
结果为
今天天气'不错'
今天天气不错
今天天气不错
在单引号内进行拼接,只可以使用成对的单引号括住定义的变量并完成拼接;直接引用和使用双引号括住均无效,只会原样输出
在双引号内进行拼接,可以使用双引号括住变量,也可以直接使用变量;如果使用单引号括住,则单引号会被打印出来
获取字符长度
花括号内,在字符串变量名前加#即可
stt="ddwmkld12"
a=${#stt}
在使用变量的时候要加{}
提取子字符串
${字符串变量名:起始位置:截取长度}
stt="ddwmkld12"
a=${stt:2:4}
echo $a
结果
wmkl
起始位置从0开始
查找字符串
#!/bin/bash
string="runoob is a great site"
# 在string字符串中找r或者o,哪个先出现就输出谁的位置
echo `expr index "$string" ro`
结果是位置偏移,从1开始,例如r的位置是1;找不到的话才输出0
expr index STRING CHARS 命令并不是查找 CHARS 子字符串在 STRING 字符串中的位置。
它只能查找单个字符在 STRING 字符串中的位置。只是 CHARS 可以指定要查找哪几个字符,并以第一个查找到的字符为准。
当 STRING 字符串的内容包含空格时,要用双引号括起来,否则会报错。
其他
字符串还有很多操作,如替换、删除等,用到再看
Shell数组
bash只支持一维数组,初始化时不需要定义数组大小
定义数组
在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:
array_name=(value0 value1 value2 value3)
还可以单独定义数组的各个分量,可以不使用连续的下标,而且下标的范围没有限制。
arr[0]=50
arr[3]=30
此时输出数组的结果是 “50 30”,但是输出arr[1]的话显示空白,arr[3]才是50
读取数组
${数组名[下标]}
使用 @ 或者 * 符号可以获取数组中的所有元素
#! /bin/bash
arr=(1 2 3 4 'sds' df)
echo ${arr[@]}
输出的结果为
1 2 3 4 sds df
获取数组的长度
和字符串的方法相同
#! /bin/bash
arr=(1 2 3 4 'sds' df)
# 获取整个数组的长度,即数组中有几个元素。以下两种都可以,结果是6
echo ${#arr[*]}
echo ${#arr[@]}
# 获取数组中单个元素(第5个-sds)的长度,结果为3
echo ${#arr[4]}
Shell注释
- 单行注释:以#开头
- 多行注释:
:<<xxx
注释内容...
注释内容...
xxx
xxx可以用任意符号代替
Shell传递参数
我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。
$0代表执行的文件名称
#!/bin/bash
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第五个参数为:$5";
传入参数时,终端进行如下操作(上述代码保存在dw.sh)
./dw.sh 1 2 3 4
结果为:
Shell 传递参数实例!
执行的文件名:./dw.sh
第一个参数为:1
第5个参数为:
因为只传入了4个参数,故$5是空白
总结常用几个参数(还有不明白的之后解释)
参数处理 | 说明 |
---|---|
$0 | 执行的文件名 |
$n | 第n个传入的参数 |
$# | 传递到脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数。 |
$@ | 与$*相同,但是使用时返回的是每个参数。 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 |
$ 与 $@ 区别:*
- 相同点:都是引用所有参数。
- 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。
#!/bin/bash
echo "$*"
# 1 2 3 4
echo "$@"
# 1 2 3 4
for i in "$*";do
echo '$*' $i
done
# $* 1 2 3 4 -- 相当于传递了“1 2 3 4”这一个参数
for j in "$@";do
echo '$@' $j
done
# $@ 1
# $@ 2
# $@ 3
# $@ 4 --- 相当于传递了"1" "2" "3" "4" 四个参数
Shell运算符
- 算数运算符
- 关系运算符
- 布尔运算符
- 字符串运算符
- 文件测试运算符
算数运算符
加、减、乘、除、取余、赋值、相等、不等 和其他语言一样
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
expr 是一款表达式计算工具,使用它能完成表达式的求值操作。语法如下
`expr $a + $b`
# 外边的不是常用的单引号,是~下边那个
#!/bin/bash
a=100;
b=20;
c=`expr $a + $b`
echo $c
乘法的不能直接使用,要用转义符 /
在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 "" 。
也可以使用[]进行计算,在[]中的乘法不需要转义字符
a=10
b=20
c=$[a+b]
echo $c
//结果为30
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
运算符 | 说明 |
---|---|
-eq | 两个数是否相等 |
-ne | 两个数是否不相等 |
-gt | 左边是否大于右边 |
-lt | 左边是否小于右边 |
-ge | 左边是否大于等于右边 |
-le | 左边是否小于等于右边 |
布尔运算符
运算符 | 说明 |
---|---|
! | 非 |
-o | 或 |
-a | 与 |
逻辑运算符
运算符 | 说明 |
---|---|
&& | 逻辑中的AND |
|| | 逻辑中的OR |
字符串运算符
运算符 | 说明 |
---|---|
=(!=) | 两个字符串是否相等(不等) |
-z | 字符串长度是否等于 0 |
-n | 字符串长度是否不等于 0 |
$ | 字符串是否不为 空 |
文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。这部分只做简单记录,后续有应用的时候在介绍
操作符 | 说明 |
---|---|
-b file | 检测文件是否是块设备文件。 |
-c file | 检测文件是否是字符设备文件。 |
-d file | 检测文件是否是目录。 |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件)。 |
-g file | 检测文件是否设置了 SGID 位。 |
-k file | 检测文件是否设置了粘着位(Sticky Bit)。 |
-p file | 检测文件是否是有名管道。 |
-u file | 检测文件是否设置了 SUID 位。 |
-r file | 检测文件是否可读。 |
-w file | 检测文件是否可写。 |
-x file | 检测文件是否可执行。 |
-s file | 检测文件是否为不空(文件大小是否大于0)。 |
-e file | 检测文件(包括目录)是否存在。 |
#!/bin/bash
file="/mnt/c/Users/taozhang/Desktop/WH_C++/Shell-/test.sh"
echo $0
if [ -e $file ]
then
echo "文件存在"
else
echo "文件不存在"
fi
file路径问题:
相对路径:当前文件夹下直接写文件名,上一级退出的话../xx.sh
绝对路径:直接看终端的复制前边部分,和文件夹下找到的路径格式不同
Shell常用命令
仅参考菜鸟教程,其余命令随时补充
echo命令
- 显示普通字符串:
echo "Hello World"
# 结果为 Hello World
- 显示转义字符串:
echo ""Hello World""
# 结果为 "Hello World"
补充一个read命令,从终端输入中读取一行,并指定给对应的变量
read name
终端运行后输入:wang xn
则再次调用name时,其内容就是"wang xn"
- 显示变量:
echo "${name} is a beautiful girl"
- 显示换行
echo -e "OK!
"
echo "It is a test"
结果为:
OK!
It is a test
运行时发现的两点总结:
在转义字符后边接特定功能时,有两种方法,以 举例:
1、空格 + :echo "wangxn "
2、-e:echo -e "wanghan "
如果直接echo "wangxn "
, 会直接打印出来,没有效果
vscode终端中,如果使用 sh xxx.sh运行,就无法识别 -e
- 显示不换行
#!/bin/bash
echo -e "OK! c"
echo -e ""hello""
结果为
OK! "hello"
- 显示结果至定向文件
echo "It is a test" > myfile
自动在当前文件路径下新建myfile文件,里边有 It is a test
如果需要在其他文件下创建文件并输出,则需要引号中写绝对(相对)路径
- 原样输出字符串,不进行转义或取变量(用单引号)
echo '$name"'
# 结果为 $name"
- 显示命令执行结果
echo `xx`
xx代表内部命令,如date就是显示当前日期的意思
printf命令
printf 使用引用文本或空格分隔的参数,外面可以在 printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。默认的 printf 不会像 echo 自动添加换行符,我们可以手动添加 。
printf 命令的语法:
printf 格式控制字符串 参数列表
- 在格式控制字符串中,%s %c %d %f 都是格式替代符,%s 输出一个字符串,%d 整型输出,%c 输出一个字符,%f 输出实数,以小数形式输出。
- %-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
- %-4.2f 指格式化为小数,其中 .2 指保留2位小数。
printf "%-10s %-8.1f
" abd 20.01
#结果为 abd 20.0
printf命令的转义序列(很多不明白,用到之后回头解释)
序列 | 说明 |
---|---|
a | 警告字符,通常为ASCII的BEL字符 |
后退 | |
c | 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略 |
f | 换页(formfeed) |
换行 | |
回车(Carriage return) | |
水平制表符 | |
v | 垂直制表符 |
一个字面上的反斜杠字符 | |
ddd | 表示1到3位数八进制值的字符。仅在格式字符串中有效 |