shell内置命令,就是由Bash Shell自身提供的命令,而不是文件系统中的可执行脚本文件。
使用type
来确定一个命令是否是内置命令,是的话会得到 XXX is a shell builtin,不是的话就会得到这个脚本文件的地址。
通常来说,内置命令会比外部命令执行得更快,执行外部命令时不但会触发磁盘I/O,还需要fork出一个单独的进程来执行,执行完成后在退出,会有上下文的切换,而执行内置命令相当于调用当前Shell进程的一个函数,还是在当前shell环境进程内,减少了上下文切换。
5.1. echo
echo是一个shell内置命令,用于在终端输出字符串,并在最后默认加上换行符。
默认换行语法:echo 字符串
-
echo hello world
# 这种加不加引号都无所谓
输出不换行语法:echo -n 字符串
-
echo -n hello
或者 echo -e “字符串\c”
echo默认是不解析特殊字符的,比如换行的\n,它还是原样输出,若是想让它解析,那就:
echo "hello wor\nld"
# 得到的就是 hello wor\nldecho -e "hello wor\nld"
# 那么\n就会换行echo -e "hello world\c"
# c就是clear,会把换行符去掉,那这里就不会再换行了
5.2. read
read是shell内置命令,用于标准输入中读取数据并赋值给变量,如果没有进行重定向,默认就是从终端控制台读取用户输入的数据;如果进行了重定向,那么可以从文件中读取数据。
- 使用read给多个变量赋值;
- 使用read读取1个字符;
- 使用read限制时间输入。
语法:read [-options] [var1 var2 …]
- options和var都是可选的,如果没有提供变量名,那么读取的数据将存放在环境变量
REPLY
变量中;
在交互式shell中:
read
abc 12 45 # 一回车就会结束
echo $REPLY # abc 12 45 (得到的)
- options,如下表所示;var表示用来存储数据的变量,可以有一个,也可以有多个。
选项 | 说明 |
-a | 把读取的数据赋值给数组array,从下标0开始 |
-d | 用字符串delimiter指定读取结束的位置, 而不是一个换行符(读取到的数据不包括delimiter) |
-e | 在获取用户输入的时候,对功能键进行编码转换, 不会直接显式功能键对应的字符。 |
-n num | 读取num个字符,而不是整行字符 |
-p prompt | 显示提示信息,提示内容为prompt |
-r | 原样读取(Raw mode),不把反斜杠字符解释为转义字符 |
-s | 静默模式(Slient mode),不会在屏幕上显示输入的字符, 输入密码或其它确认信息时常用, |
-t seconds | 设置超时时间,如果用户没有在指定时间内输入完成 那么read将会返回一个非0的退出状态,表示读取失败。 |
-u fd | 使用文件描述符fd作为输入源,而不是标准输入, 类似于重定向。 |
示例一:同时给多个变量赋值
vim一个read1.sh文件:
#!/bin/bash
read -p "请输入姓名,年龄,爱好:" name age hobbit
#打印每一个变量
echo "姓名:${name}"
echo "年龄:${age}"
echo "爱好:${hobbit}"
编辑完保存后,执行命令bash read1.sh +在同一行输入这三个值,用空格隔开,好比:bash read1.sh 张三 13 喜欢游泳
就可以看到输出结果,这几个变量也只能在这个shell脚本中使用。
示例二:只接受一个字符
vim一个read2.sh文件:
#!/bin/bash
# 下面的-n和-p的顺序是没有影响的
read -n 1 -p "您确定要删除数据吗?(请输入y/n):" a_char
printf "\n" # 这是换行,可以只用一个 echo,单用它就是换行
echo "您输入的字符:${a_char}"
加个-n参数后,在提示输入后,在输入一个字符后,就会直接进入到下一行命令,不需要用户回车,这里直接执行sh read2.sh
或bash read2.sh
。
实例三:时间限制|密码静默
#!/bin/bash
read -t 10 -sp "请输入密码(10s内):" pwd1
echo # 这是换行(使用了-s静默模式才需要这个换行符)
read -t 10 -sp "请再次输入密码(10s内):" pwd2
printf "\n"
# 校验密码两次是否一致
if [ $pwd1 == $pwd2 ] # 这里变量名前后一定都要有空格
then
echo "两次密码一致,认证通过~"
else
echo "密码不一致,验证失败!"
fi
-s就是让密码的输入不显示出来;
-t时间超过了,就好像会默认给空再执行下去。
5.3. exit
exit应用场景:
- 直接结束当前shell进程;
- 还可以返回不同的状态码,进程结束后用
echo $?
查看;
#!/bin/bash
echo "hello" nihao
exit 1 # 执行到这里就会退出,下面一句就不会执行了
echo "world"
我们一般定义0为程序正常执行,然后可以自定义其它一般0~255的值去代表不同的状态、程序出错的原因。
5.4. declare
介绍:declare命令用于声明shell变量,可用来声明变量并设置变量的属性,也可用来显示shell函数。若不加上任何参数,则会显示全部的shell变量与函数(与单独执行set命令的效果想通过)。
declare命令作用:
- declare可设置变量的属性(直接使用age=20赋值变量,得到的都是字符串,可用这让20成为整形);
- 单独使用查看全部shell变量与函数;
- 实现关联数组变量(可理解为key成了字符串,前面的数组的索引都是数字)。
语法:declare [x/-][aArxif] [变量名称=具体值]
+/-
:-
用来指定变量有该属性,+
是取消该属性;a
:array,设置为普通索引数组(跟前面数组是一样的);A
:Array,设置为key-value关联数组(索引是字符串);r
:readonly,将变量设置为只读,也可以使用readonly;x
:export,设置变量为环境变量,也可以使用export;i
:int,设置变量为整形变量;f
:function,设置为一个函数变量。
-
declare -f
:查询所有函数的定义; -
declare -F
:查询所有的函数列表。
示例:操作一个变量,设置为整形\取消整形\设置为只读等操作
在交互式shell下(声明变量时,默认这个变量都是字符串):
declare -i age=24 # 设置一个整形变量(不加-i,24就是字符串)
age="abc"; echo $age # 得到的是0,因为age设定的是整形,重新赋值为字符串就是错的,就会变成0
declare +i age # 把整形属性取消
age="efg"; echo $age # 这里得到的就是efg
declare -r name=abc #或者 readonly name=abc
name=efg # 错的,不被允许,name成为了只读
key-value关联数组
关联数组也称为“键值对(key-value)数组”,即key是字符串的形式称为数组下标,语法(关键参数-A
):
declare -A 数组名=([字符串key1]=值1 [字符串key2]=值2 ...)
获取指定key的值:${关联数组名[key]}
;
获取所有的值:${关联数组名[*]}
或${关联数组名[@]}
;
当然declare也可以创建定义普通索引数组(关键参数-a
):declare -a 数组名=(值1 值2 ...)
或declare -a 数组名=([0]=值1 [1]=值2 ...)
# 这跟这一样
简单示例:vim一个abc.sh,内容如下
#!/bin/bash
# 普通数组
declare -a arr1=("zhangsan" 13 my_shell)
echo ${arr1[*]} # 千万别忘了这里的花括号
echo ${arr1[1]}
declare -a arr2=([0]="lisi" 14 li_shell)
echo ${arr2[@]}
# 关联数组
declare -A arr3=(["name"]="wangwu" [age]=15 [hobbit]="shell")
echo ${arr3[@]}
echo ${arr3["age"]}
Tips:
- 会发现无论是键还是值,引号都是可要可不要的。
- 不用declare -A声明关联数组,而是直接像普通数组一样,那么是无法用key去获取值得,在交互式shell下:
arr=(["one"]=abc ["two"]=efg ["three"]=xyz)
echo $arr #
echo ${arr[one]} # 这三个得到的都是 xyz
echo ${arr[two]} #
5.5 test
shell中的test命令用于检查某个条件是否成立,它可以进行数值、字符串和文件三个方面的测试,功能与[ ]
一样,一般两种用法:
- 交互式shell:test 表达式1 options 数字2
test 1 == 1 ;echo $?
# 得到的就是 0 - .sh脚本文件:
if test 表达式1 options 表达式2
then
…
fi
实例:test -w /root/123.sh -a 2 \> 1 -o 123 -eq 123 ; echo $?
# 得到的就是 0,代表执行成功。
- 第一个条件是文件测试运算符,直接用;
- 每个条件间的逻辑运算符连接是用的
-a
、-o
,是不能用&&、||的(这必须要在[[ ]]
或是(( ))
中使用); - 可以直接使用判等、大于小于,但是记得转义符;
- 注意,在只有数字的比较时是可以用-eq、-gt这些的;
- 这些表达式及符号的具体用法及其限制我会在后续中陆续讲解。