其他连接:
shell中各种括号的作用'()''{}''[]'
等
Shell 环境
他扩展名一般为sh, 不起作用就是为了见名知意。
shell脚本的执行方法一定为./test.sh, 不能少了./, 少了就是去PATH(/bin, /sbin, /usr/bin,/usr/sbin
)寻找了。
一般shell脚本需要在第一行确定解释器,比如#!/bin/bash
, Linux 的 Shell 种类众多,常见的有:
bash
Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)
......
Bash 也是大多数Linux 系统默认的 Shell。
1. Shell 变量
正确定义变量,下面举几个例子,判断正误:
bash
your_name = "runoob" (x)变量名和等号之间不能有空格。
0your_name="runoob" (x)不能以数字开头
then="runoob" (x)不能用shell关键字
?your_n&ame="runoob" (x)不能用特殊符号
pi=3.1415926 (x)常量要大写,小写不推荐
your name="runoob" (x)不能有空格
your_name="runoob" (√)
RUNOOB="www.runoob.com"(√)
LD_LIBRARY_PATH="/bin/"(√)
_var="123"(√)
var2="abc"(√)
我蹦出来一个问题:看上面都在用双引号,单引号可以吗?
shell中定义字符串变量(shell默认变量为字符串)用双引号和单引号以及不用引号的区别 :
单引号:所见即所得,强引用。
双引号:弱引用,如果其中有命令,变量,特殊转义,会解析后再输出结果。
无引号:shell遇到空格会阶段,有可能得不到想要的
比如:
1.1 使用变量
变量名前面加美元符号即可,加{}是为了做区分 ,有时候不区分会造成混淆,都加上{}
养成良好编程习惯,比如下面这种造成混淆:
bash
for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done
for skill in Ada Coffe Action Java; do
echo "I am good at $skillScript" #这得不到想要的结果
done
变量定义后可以重新赋值,方法是:
bash
name="tom"
echo ${name}
name="lily"
echo ${name}
$mame="lily" #这行会报错,只有使用变量时才用$
只读变量不能被改变:
bash
myUrl="https://www.google.com"
readonly myUrl
myUrl="https://www.runoob.com" #这行会报错
删除变量
bash
myUrl="https://www.google.com"
readonly myUrl
name="tom"
echo ${name}
unset name
echo ${name} #会输出空行,但没报错
unset myUrl #会报错,不让删除
1.2 变量类型:
分:字符串,整数,数组,环境,特殊 这几种变量。
字符串变量 :用单引号 ' 或双引号 " 来定义字符串。
整数变量 :可以用declare声明一下,比如:declare -i my_integer=42
声明告诉 Shell 将 my_integer 视为整数。
数组变量:比如:
c
my_array=(1 2 3)
for num in "${my_arry[@]}"; do
echo ${num}
done
bash
#运行结果
1
2
3
c
#关联数组变量
declare -A associative_array
associative_array["name"]="John"
associative_array["age"]=30
for element in "${associative_array[@]}"; do
echo "$element"
done
bash
#运行结果
30
John
1.3 环境变量
环境变量为系统或用户设置的特殊变量,用于限制行为或影响环境,常用的有:
参考博客:[Tips] Shell中常用的环境变量与自定义环境变量
pwd
:这个在shell中断的命令也可也(在使用时,我发现这个命令只有使用小括号()括起来才有效,即$(pwd)
,其他形式没用 ,所以请看shell中各种括号的作用)
HOME
: 使用者的/~目录地址
BASH
: 目前使用的shell
PATH
:系统默认的可执行文件搜索路径
LANG
:系统使用的编码。很多程序是根据系统指定的编码去解析输入文件,如果编码不正确,很多文件就无法正确解析。
RANDOM
:随机产生一个0~32767之间的随机数
$$
:表示当前shell的pid
$0
:表示脚本名称
$1
:表示脚本第一个参数,$2就是第二个参数
$#
:为传递给shell的参数数量
$?
:为上一个命令的退出状态
1.4. Shell 字符串变量
shell字符串最常用,最有用,可以单引号,双引号,也可也不用引号。刚刚我说了使用他们的区别,单引号是强转,双引号要转换一下。但是还有一些好玩的没讲:
1.4.1 字符串拼接
c
your_name="lily"
greeting="Hi, ${your_name}."
greeting_1="Hi, \"$your_name\"."
echo ${greeting} ${greeting_1}
结果是
c
Hi, lily. Hi, "lily".
单引号没这效果呦。
1.4.2 获取字符串长度
其实就是加了个#号呗。
c
string="abcde"
echo ${#string}
echo ${#string[0]}
结果是
c
5
5
1.4.3 提取子字符串
c
string="runoob is a great site"
echo ${string:2:4}
echo ${string:2:7}
string后接:索引:长度。
字符串第一个字母索的引为0,结果你猜一猜
c
noob
noob is
1.4.3 查找字符所在位置
查找字符 i 或 o 在字符串中第几个子字母位置(第一个字母位置为0)哪个先出现就返回哪个。
c
string="runoob is a great site"
echo `expr index "$string" is` # 其中 ` 是反引号
echo `expr index "$string" i` # 其中 ` 是反引号
echo `expr index "$string" s` # 其中 ` 是反引号
答案猜一下:
c
8
8
9
1.5 数组变量
仅支持一维数组,不支持多维。
使用下标表示成员与c语言类似。
下表中可以为数字或算数表达式。
1.5.1 定义数组
shell中用空格来定义数组,元素之间用空格分开。
c
数组名=(值1 值2 值3 ... 值n)
可以这样定义:
c
array_name=(
value0
value1
value2
value3
)
也可也分别定义数组的各个元素:
c
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
array_name[7]=value7
for value in ${array_name[@]}; do
echo ${value}
done
可以不使用连续的下标,而且下标的范围没有限制, 结果是:
c
value0
value1
value2
value7
1.5.2 读取数组
1.5.3 获取数组的长度
获取数组成员个数,以及获取某成员长度,加 #
:
c
array_name[0]=value0
array_name[1]=value01
array_name[2]=value012
array_name[7]=value01234567
length1=${#array_name[*]} #获取数组成员个数
echo "length1=${#length1}"
length2=${#array_name[@]} #获取数组成员个数
echo "length2=${#length2}"
length3=${#array_name[7]} #获取某数组成员 的 字符串长度
echo "length3=${#length3}"
echo "array_name=${array_name[@]}" #获取全部成员
echo "array_name=${array_name[*]}" #获取全部成员
揭晓答案:
c
length1=4
length2=4
length3=13
array_name=value0 value01 value012 value01234567
array_name=value0 value01 value012 value01234567
2. Shell 注释
以 # 开头的行就是注释,会被解释器忽略。
多行注释可以是这样的,不咋用,详情看看shell注释:
c
: <<'COMMENT'
这是注释的部分。
可以有多行内容。
COMMENT
3. 传递参数
前面说了,使用美元符号加数字来传递参数。例如:
c
不举例子了,太简单,比如:
./test.sh 11 22 33
其中test.sh中的内容为:
#!/bin/bash
echo $0
echo $1
echo $2
echo $3
运行结果为:
c
./test.sh
11
22
33
在前面1.3一节总结了一些特殊参数,不全,再汇总一下
参数 | 解释 |
---|---|
$# | 脚本输入参数的个数 |
$* | 当用""括起来,输出所有参数为"参数1 参数2 ..." |
$? | 判断退出状态 |
$! | 最后运行的进程的ID号 |
$@ | 当用""括起来,输出所有参数格式为:"参数2" "参数1" ... |
$- | 显示Shell使用的当前选项,与set命令功能相同 |
$$ | shell脚本所在进程ID号 |
其中$*
与$#
的不同比较难理解,看个例子就懂了:
c
echo "-- \$* 演示 ---"
for i in "$*"; do
echo $i
done
echo "-- \$@ 演示 ---"
for i in "$@"; do
echo $i
done
c
#./test.sh 11 22 33
# 结果为:
-- $* 演示 ---
11 22 33
-- $@ 演示 ---
11
22
33
4. 数组
之前介绍了数组变量,咱也稍微熟悉了,知道shell中只存在一维数组,不存在高维数组。数组用括号来表示,元素之间用空格分隔,第一个元素索引为0,而且可以分别定义元素的值且可以不连续。
例子:
c
array_name=(value1 value2 ... valuen)
读取数组元素的值:使用美元符号,养成使用{}的好习惯,格式如下:
c
${array_name[index]}
关联数组
概念:可以使用任意字符串作为下标来访问数组元素。听着挺唬人的哈,其实就是键值对儿。直接举例子:
c
declare -A array_name # 声明一个关联数组
array_name["xiaoming"]="good boy"
array_name["xiaohong"]="good girl"
array_name["zhangsan"]="luck dog"
echo ${array_name["xiaohong"]}
输出就是good girl
使用 @
或 *
可以获取数组中的所有元素 ,加上#
可以获取数组成员个数或者单个成员字符个数,都在1.5 数组变量这一小节已经讲过了,去复习吧。
5. 运算符
shell中有算数,关系,布尔,字符串,文件运算符等,bash不支持简单的数学运算,但是可以通过其他命令实现,举例子用expr
表达式计算工具实现两数相加:
bash
#!/bin/bash
val=`expr 2 + 2`
echo "两数之和为 : $val"
val1='expr 2 + 2' # 不是单括号,而是反引号,注意啊
echo "两数之和为 : $val1"
val2=`expr 2+2` # 表达式与运算符之间要有空格
echo "两数之和为 : $val2"
输出结果:
bash
两数之和为 : 4
两数之和为 : expr 2 + 2
两数之和为 : 2+2
5.1 算数运算符
包括+ - * / % = == !=
这些。但需要注意:
+ - * / %
需要用expr
表达式,遵守expr
表达式规范。
其中乘法*
运算符需要加反斜杠\
才能实现乘法运算,即:
c
val=`expr $a \* $b`
=
经常用,两边不能有空格我就不说了。
== !=
这两个条件表达式 要放在中括号[]
里,且必须要有空格 ,强烈建议只能用于字符串比较,不要用于整数比较,整数比较用关系运算符(如果发现被比较对象不是数组会报警告的)。
比如:a=str, b=str
, [ $a == $b ]
四个空格为正确,即 取值运算必须被空格包围 , [$a==$b]
错误 ,[$a == $b]
也错误 ,就是说正确表达中空格少任何一个会报错command not found
。
5.2 关系运算符
关系运算符只支持数字 ,不支持字符串,除非字符串的值是数字,多用于if
语句。假定变量 a=10
,b=20
举例说明:
关系运算符 | 含义 | 举例 |
---|---|---|
-eq |
equal | [ $a -eq $b ] false |
-ne |
not equal | [ $a -ne $b ] true |
-gt |
greater than | [ $a -gt $b ] false |
-lt |
less than | [ $a -lt $b ] true |
-ge |
greater and equal | [ $a -ge $b ] false |
-le |
less and equal | [ $a -le $b ] true |
5.3 布尔运算符
共三个:!
,-a
,-o.
, 简单猜一下哪个是取反,and运算符 ,or运算符?
恭喜你,猜对了。呱唧呱唧!
备注:用在 [ ... ] 内部组合条件(如 test 命令)
举例子:
bash
a=10
b=300
if [$a -gt 5 -a $a -lt 15]; then
echo "a greater than 5 and a less than 15, true"
else
echo "a greater than 5 and a less than 15, false !"
fi
if [ $b -gt 100 -a $b -lt 200 ]; then
echo "b greater than 100 and b less than 200, true"
else
echo "b greater than 100 and b less than 200, false !"
fi
如果你细心的话,会发现上面的代码有一行是错误的。
且你运行会发现,这个错误不会报错没有提示。好尼玛隐蔽的错误。
提示:有一行少了两个空格,请修正代码。
下面是修正代码后的输出:
bash
a greater than 5 and a less than 15, true
b greater than 100 and b less than 200, false !
5.4 逻辑运算符
俩:&&
和 ||
,是实现逻辑AND与OR的两个命令,我新生疑惑,这跟5.3的布尔运算符不重了吗?
问题:布尔运算符 -a -o 与 逻辑运算符 && || 在使用时的差异?
答:
布尔运算符:可用于test命令,即 [ ... ] 内部。
逻辑运算符:是shell本身的逻辑与或操作符,用于连接两个独立的命令,可用于控制执行流程。
例1:
bash
mkdir dir && cd dir # 创建目录成功后进入
grep "hello" file.txt || echo "Not found" # 未找到文本时提示
上面这里的逻辑运算符不能被替换为布尔运算符
例2:
bash
if [ $b -gt 100 -a $b -lt 200 ]; then
...
上面的布尔运算符不能被替换为&&,会报错的
如果想要使用&&实现相同的逻辑有两种方法,
bash
# 法1使用双中括号,原理参见篇首链接
if [[ $b -gt 100 && $b -lt 200 ]]; then
# 法2,拆封成两个单独的命令,保证逻辑运算符用于连接两个单独的命令的规则
if [ $b -gt 100 ] && [ $b -lt 200 ]; then
5.5 字符串运算符
有五个,=
,!=
,-z
(长度为0),-n
(长度不为0),$
。
分别用于:检查两个字符串,相等,不等,长度是否为0,长度是否不为0,是否为空字符串。
注意事项 1 :=
是 POSIX 标准,==
是 Bash 扩展,虽然都能实现字符串比较,但推荐使用=
。
注意事项 2 :字符串变量在test进行取值比较时,变量取值操作需要加上双引号""
,防止字符串存在空格导致的语法错误
注意事项 3 :-n
与$
都能实现检查字符串长度,但推荐使用前者,更容易理解。
举例,看看不加双引号的可能的后果:
bash
b="a b"
if [ -n "$b" ]; then
echo "字符串长度不为0"
fi
if [ -n "$b" ]; then
echo "字符串长度不为0"
fi
输出,看报错了吧:
bash
字符串长度不为0
./test.sh: line 38: [: a: binary operator expected
5.6 文件测试运算符
-c
:检测文件是否字符设备
-b
:检测文件是否块设备
-d
:检测文件是目录
-f
:是否普通文件
-r
:文件是否可读
-w
:文件是否可写
-x
:文件是否可执行
还有一堆,看个例子吧:
bash
if [ -d "/root/test/" ]; then
echo "this is driectory"
fi
5.7 自增和自减操作符
本节主要讲解几点,暂时用的不多,到时候再学:
使用 let 命令进行算数运算;
使用 $(( )) 进行算术运算;
使用 expr 进行算术运算;
使用 (( )) 进行算术运算;
6. echo命令
- 显示普通字符串:
echo "It is a test"
注意使用双引号。 - 显示转义字符,跟c语言的printf用法差不多
echo "\"It is a test\""
- 显示变量:
c
#!/bin/sh
read name //read命令从标准输入读入一行并把值给到name变量
echo "$name"
以下为输出结果
[root@www ~]# sh test.sh
OK123 #标准输入
OK123 #输出
- 显示换行:
bash
echo -e "OK! \n" # -e 开启转义
echo -e "OK! \c" # -e 开启转义 \c 不换行
- 重定向到文件
bash
echo "It is a test" > myfile
- 单引号不进行转义
bash
echo '$name\"'
输出结果
$name\"
7. printf命令
暂时没学,没见过
8. test命令
在 POSIX 标准中定义。[ 实际上是一个命令名,与 test 功能完全相同,但需要以 ] 结尾。比如说:
bash
[ -f "file.txt" ] # 等价于 test -f "file.txt"
尽管功能相同,但 [ ... ] 更符合 shell 脚本的传统和可读性.
提示:无论用 test 还是 [ ... ],变量必须用双引号保护,防止空值或空格导致语法错误。
9. 流程控制
9.1 if 语句
写成一行适用于中断命令提示符:
c
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
bash
if condition1; then
command1
elif condition2 ; then
command2
else
commandN
fi
经常与 test 命令结合使用,也就是用[], 使用时注意到处都是空格。
9.2 for 循环
c
for i in {1..5} ; do
echo "The value is: $i"
done
也可换成:for ((i=1; i<5; i++)) ; do
9.3 while 循环
bash
a=1
while [ $a -lt 5 ]; do
echo "a = $a"
let "a++" #也可换成 a=`expr $a + 1`
done
bash
echo '按下 <CTRL-D> 退出'
echo -n '输入你最喜欢的网站名: '
while read FILM
do
echo "是的!$FILM 是一个好网站"
done
当while后面没东西就是无线循环了(没试):
c
while :
do
command
done
9.4 until 循环
使用 until 命令来输出 0 ~ 9 的数字:
bash
b=0
until [ $b -gt 9 ]; do
echo "b = $b"
let "b++" #也可换成b=`expr $b + 1`
done
9.5 case 语句
case ... esac 为多选择语句,与其他语言中的 switch ... case 语句类似,记住结构:
bash
#!/bin/sh
site="google"
case "$site" in
"baidu") echo "百度"
;;
"google") echo "Google 搜索"
;;
"taobao") echo "淘宝网"
;;
esac
9.6 break 与 continue
break 命令允许跳出所有循环(终止执行后面的所有循环)。
continue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。