Shell入门
Shell 变量
your_name="qinjx"
echo $your_name
echo ${your_name}
for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done
如果不给skill变量加花括号,写成echo "I am good at $skillScript",解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。
推荐给所有变量加上花括号,这是个好的编程习惯。
删除变量
使用 unset 命令可以删除变量。语法:
unset variable_name
#!/bin/sh
myUrl="http://c.biancheng.net/shell/"
unset myUrl
echo $myUrl
没任何输出
Shell 中有两种方式可以完成命令替换,一种是反引号,一种是
$()
,使用方法如下:
variable=`commands`
variable=$(commands)
其中,variable 是变量名,commands 是要执行的命令。commands 可以只有一个命令,也可以有多个命令,多个命令之间以分号`;`分隔。
例如,date 命令用来获得当前的系统时间,使用命令替换可以将它的结果赋值给一个变量。
data是一个命令
#!/bin/bash
begin_time=`date` #开始时间,使用``替换
sleep 20s #休眠20秒
finish_time=$(date) #结束时间,使用$()替换
echo "Begin time: $begin_time"
echo "Finish time: $finish_time"
运行脚本,20 秒后可以看到输出结果:
Begin time: 2019年 04月 19日 星期五 09:59:58 CST
Finish time: 2019年 04月 19日 星期五 10:00:18 CST
Shell $?:获取函数返回值或者上一个命令的退出状态
1) $? 获取上一个命令的退出状态
编写下面的代码,并保存为 test.sh:
#!/bin/bash
if [ "$1" == 100 ]
then
exit 0 #参数正确,退出状态为0
else
exit 1 #参数错误,退出状态1
fi
exit
表示退出当前 Shell 进程,我们必须在新进程中运行 test.sh,否则当前 Shell 会话(终端窗口)会被关闭,我们就无法取得它的退出状态了。
例如,运行 test.sh 时传递参数 100:
[mozhiyan@localhost ~]$ cd demo
[mozhiyan@localhost demo]$ bash ./test.sh 100 #作为一个新进程运行
[mozhiyan@localhost demo]$ echo $?
0
再如,运行 test.sh 时传递参数 89:
[mozhiyan@localhost demo]$ bash ./test.sh 89 #作为一个新进程运行
[mozhiyan@localhost demo]$ echo $?
1
2) $? 获取函数的返回值
编写下面的代码,并保存为 test.sh:
#!/bin/bash
#得到两个数相加的和
function add(){
return `expr $1 + $2`
}
add 23 50 #调用函数
echo $? #获取函数返回值 73
变量类型
运行shell时,会同时存在三种变量:
- 1) 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
- 2) 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
- 3) shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
your_name="runoob"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2 $greeting_3
获取字符串长度
string="abcd"
echo ${#string} #输出 4
提取子字符串
以下实例从字符串第 2 个字符开始截取 4 个字符:
string="runoob is a great site"
echo ${string:1:4} # 输出 unoo
查找子字符串
查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):
string="runoob is a great site"
echo `expr index "$string" io` # 输出 4
以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。
Shell 数组
在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:
array_name=(value0 value1 value2 value3)
array_name=(
value0
value1
value2
value3
)
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen
读取数组
读取数组元素值的一般格式是:
${数组名[下标]}
例如:
valuen=${array_name[n]}
使用 @ 符号可以获取数组中的所有元素,例如:
echo ${array_name[@]}
使用@或*可以获取数组中的所有元素,例如:
${nums[*]}
${nums[@]}
获取数组的长度
获取数组长度的方法与获取字符串长度的方法相同,例如:
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}
my_array=(A B "C" D)
echo "第一个元素为: ${my_array[0]}" # A
echo "第二个元素为: ${my_array[1]}" # B
echo "数组的元素为: ${my_array[*]}"#数组的元素为: A B C D
echo "数组的元素为: ${my_array[@]}"#数组的元素为: A B C D
#!/bin/bash
nums=(29 100 13)
echo ${#nums[*]}
#向数组中添加元素
nums[10]="http://c.biancheng.net/shell/"
echo ${#nums[@]}
echo ${#nums[10]}
#删除数组元素
unset nums[1]
echo ${#nums[*]}
运行结果:
3
4
29
3
数组的拼接
所谓 Shell 数组拼接(数组合并),就是将两个数组连接成一个数组。
拼接数组的思路是:先利用@或*,将数组扩展成列表,然后再合并到一起。具体格式如下:
array_new=(${array1[@]} ${array2[@]})
array_new=(${array1[*]} ${array2[*]})
两种方式是等价的,选择其一即可。其中,array1 和 array2 是需要拼接的数组,array_new 是拼接后形成的新数组。
下面是完整的演示代码:
#!/bin/bash
array1=(23 56)
array2=(99 "http://c.biancheng.net/shell/")
array_new=(${array1[@]} ${array2[*]})
echo ${array_new[@]} #也可以写作 ${array_new[*]}
运行结果:
23 56 99 http://c.biancheng.net/shell/
Shell 注释
以 # 开头的行就是注释,会被解释器忽略。
通过每一行加一个 # 号设置多行注释,像这样:
#--------------------------------------------
# 这是一个注释
# author:菜鸟教程
# site:www.runoob.com
# slogan:学的不仅是技术,更是梦想!
#--------------------------------------------
##### 用户配置区 开始 #####
#
#
# 这里可以添加脚本描述信息
#
#
##### 用户配置区 结束 #####
如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?
每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。
多行注释
多行注释还可以使用以下格式:
:<<EOF
注释内容...
注释内容...
注释内容...
EOF
EOF 也可以使用其他符号:
:<<'
注释内容...
注释内容...
注释内容...
'
:<<!
注释内容...
注释内容...
注释内容...
!
Shell 传递参数
我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……
实例
以下实例我们向脚本传递三个参数,并分别输出,其中 $0 为执行的文件名(包含文件路径):
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
为脚本设置可执行权限,并执行脚本,输出结果如下所示:
$ chmod +x test.sh
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3
另外,还有几个特殊字符用来处理参数:
参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。
如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
echo "Shell 传递参数实例!";
echo "第一个参数为:$1";
echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";
执行脚本,输出结果如下所示:
$ chmod +x test.sh
$ ./test.sh 1 2 3
Shell 传递参数实例!
第一个参数为:1
参数个数为:3
传递的参数作为一个字符串显示:1 2 3
另外,还有几个特殊字符用来处理参数:
参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。
如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
echo "Shell 传递参数实例!";
echo "第一个参数为:$1";
echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";
执行脚本,输出结果如下所示:
$ chmod +x test.sh
$ ./test.sh 1 2 3
Shell 传递参数实例!
第一个参数为:1
参数个数为:3
传递的参数作为一个字符串显示:1 2 3
$* 与 $@ 区别:
相同点:都是引用所有参数。
不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
echo "-- \$* 演示 ---"
for i in "$*"; do
echo $i
done
echo "-- \$@ 演示 ---"
for i in "$@"; do
echo $i
done
执行脚本,输出结果如下所示:
$ chmod +x test.sh
$ ./test.sh 1 2 3
-- $* 演示 ---
1 2 3
-- $@ 演示 ---
1
2
3
Shell 基本运算符
算术运算符
下表列出了常用的算术运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | expr $a + $b 结果为 30。 |
- | 减法 | expr $a - $b 结果为 -10。 |
* | 乘法 | expr $a \* $b 结果为 200。 |
/ | 除法 | expr $b / $a 结果为 2。 |
% | 取余 | expr $b % $a 结果为 0。 |
= | 赋值 | a=$b 将把变量 b 的值赋给 a。 |
== | 相等。用于比较两个数字,相同则返回 true。 | [ $a == $b ] 返回 false。 |
!= | 不相等。用于比较两个数字,不相同则返回 true。 | [ $a != $b ] 返回 true。 |
**注意:**条件表达式要放在方括号之间,并且要有空格,例如: [ a = = a== a==b] 是错误的,必须写成 [ $a == $b ]。
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
a=10
b=20
val=****expr** $a + $b**
echo “a + b : $val”
val=****expr** $a - $b**
echo “a - b : $val”
val=****expr** $a \***** $b**
echo “a * b : $val”
val=****expr** $b **/** $a**
echo “b / a : $val”
val=****expr** $b **%** $a**
echo “b % a : $val”
if [ $a == $b ]
then
echo “a 等于 b”
fi
if [ $a != $b ]
then
echo “a 不等于 b”
fi
执行脚本,输出结果如下所示:
a + b : 30
a - b : -10
a * b : 200
b / a : 2
b % a : 0
a 不等于 b
布尔运算符
下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。非,并非不等于( != ) | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 or | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 and | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。equit | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 ont equit | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 greater than | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 less than | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
逻辑运算符
以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| | 逻辑的 OR | [[ $a -lt 100 |
字符串运算符
下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否不相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否不为 0,不为 0 返回 true。 | [ -n “$a” ] 返回 true。 |
$ | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
文件测试运算符
操作符 | 说明 | 举例 |
---|---|---|
-b file | 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $file ] 返回 false。 |
-c file | 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -c $file ] 返回 false。 |
-d file | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] 返回 false。 |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $file ] 返回 true。 |
-g file | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $file ] 返回 false。 |
-k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ] 返回 false。 |
-p file | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ] 返回 false。 |
-u file | 检测文件是否设置了 SUID 位,如果是,则返回 true。 | [ -u $file ] 返回 false。 |
-r file | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ] 返回 true。 |
-w file | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ] 返回 true。 |
-x file | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] 返回 true。 |
-s file | 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ] 返回 true。 |
常用函数echo print
echo 显示换行
我们可以添加-e
参数来让 echo 命令解析转义字符。例如:
echo -e "OK! \n" # -e 开启转义 \n换行
echo "It is a test"
echo 显示不换行
我们可以添加-e
参数来让 echo 命令解析转义字符。例如:
#!/bin/sh
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"
不换行
echo 命令输出结束后默认会换行,如果不希望换行,可以加上-n参数,如下所示:
echo -n "${name} is ${age} years old, "
echo -n "${height}cm in height "
echo 显示结果定向至文件
echo "It is a test" > myfile
接下来,我来用一个脚本来体现 printf 的强大功能:
printf函数
*#!/bin/bash*
*# author:菜鸟教程*
*# url:www.runoob.com*
**printf** "%-10s %-8s %-4s**\n**" 姓名 性别 体重kg
**printf** "%-10s %-8s %-4.2f**\n**" 郭靖 男 66.1234
**printf** "%-10s %-8s %-4.2f**\n**" 杨过 男 48.6543
**printf** "%-10s %-8s %-4.2f**\n**" 郭芙 女 47.9876
执行脚本,输出结果如下所示:
姓名 性别 体重kg
郭靖 男 66.12
杨过 男 48.65
郭芙 女 47.99
%s %c %d %f 都是格式替代符,%s 输出一个字符串,%d 整型输出,%c 输出一个字符,%f 输出实数,以小数形式输出。
%-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
%-4.2f 指格式化为小数,其中 .2 指保留2位小数。四舍五入
*#!/bin/bash*
*# author:菜鸟教程*
*# url:www.runoob.com*
*# format-string为双引号*
**printf** "%d %s**\n**" 1 "abc"
*# 单引号与双引号效果一样*
**printf** '%d %s\n' 1 "abc"
*# 没有引号也可以输出*
**printf** **%**s abcdef
*# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用*
**printf** **%**s abc def
**printf** "%s**\n**" abc def
**printf** "%s %s %s**\n**" a b c d e f g h i j
*# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替*
**printf** "%s and %d **\n**"
执行脚本,输出结果如下所示:
1 abc
1 abc
abcdefabcdefabc
def
a b c
d e f
g h i
j
and 0
Shell 流程控制
以下实例判断两个变量是否相等:
iF流程控制
test 通常和 if 语句一起使用,并且大部分 if 语句都依赖 test。
read age
if test $age -le 2; then
echo "婴儿"
elif test $age -ge 3 && test $age -le 8; then
echo "幼儿"
elif [ $age -ge 9 ] && [ $age -le 17 ]; then
echo "少年"
elif [ $age -ge 18 ] && [ $age -le 25 ]; then
echo "成年"
elif test $age -ge 26 && test $age -le 40; then
echo "青年"
elif test $age -ge 41 && [ $age -le 60 ]; then
echo "中年"
else
echo "老年"
fi
a=10
b=20
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
elif [ $a -lt $b ]
then
echo "a 小于 b"
else
echo "没有符合的条件"
fi
result ---> a 小于 b
num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
echo '两个数字相等!'
else
echo '两个数字不相等!'
fi
read age
if (( $age <= 2 )); then
echo "婴儿"
elif (( $age >= 3 && $age <= 8 )); then
echo "幼儿"
elif (( $age >= 9 && $age <= 17 )); then
echo "少年"
elif (( $age >= 18 && $age <=25 )); then
echo "成年"
elif (( $age >= 26 && $age <= 40 )); then
echo "青年"
elif (( $age >= 41 && $age <= 60 )); then
echo "中年"
else
echo "老年"
fi
For循环
案例1:
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
结果:
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
案例2:
#!/bin/bash
for str in This is a string
do
echo $str
done
输出结果:
This
is
a
string
#!/bin/bash
for((i=1;i<=5;i++));do
echo "这是第 $i 次调用";
done;
while 语句
实例
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
运行脚本,输出:
1
2
3
4
5
echo '按下 <CTRL-D> 退出'
echo -n '输入你最喜欢的网站名: '
while read FILM
do
echo "是的!$FILM 是一个好网站"
done
按下 <CTRL-D> 退出
输入你最喜欢的网站名:菜鸟教程
是的!菜鸟教程 是一个好网站
无限循环
while true
do
command
done
while :
do
command
done
CASE …ESAC等价于switch
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
案例
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac
#!/bin/sh
site="runoob"
case "$site" in
"runoob") echo "菜鸟教程"
;;
"google") echo "Google 搜索"
;;
"taobao") echo "淘宝网"
;;
esac
跳出循环break continue
break命令
break命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字:"
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
break
;;
esac
done
执行以上代码,输出结果为:
输入 1 到 5 之间的数字:3
你输入的数字为 3!
输入 1 到 5 之间的数字:7
你输入的数字不是 1 到 5 之间的! 游戏结束
continue
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
对上面的例子进行修改:
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字: "
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的!"
continue
echo "游戏结束"
;;
esac
done
运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句 echo “游戏结束” 永远不会被执行。
Shell 函数
[ function ] funname [()]
{
action;
[return int;]
}
function函数标识可以省略
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
funWithReturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"
结果:
这个函数会对输入的两个数字进行相加运算...
输入第一个数字:
1
输入第二个数字:
2
两个数字分别为 1 和 2 !
输入的两个数字之和为 3 !
函数参数
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
funWithParam(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "第十个参数为 $10 !"
echo "第十个参数为 ${10} !"
echo "第十一个参数为 ${11} !"
echo "参数总数有 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
输出结果:
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
字符串的连接和单引号双引号区别和字符串拼接
下面我们说一下三种形式的区别:
- 由单引号
' '
包围的字符串:
- 任何字符都会原样输出,在其中使用变量是无效的。
- 字符串中不能出现单引号,即使对单引号进行转义也不行。
- 由双引号
" "
包围的字符串:
- 如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出。
- 字符串中可以出现双引号,只要它被转义了就行。
- 不被引号包围的字符串
- 不被引号包围的字符串中出现变量时也会被解析,这一点和双引号
" "
包围的字符串一样。 - 字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。
我们通过代码来演示一下三种形式的区别:
#!/bin/bash
n=74
str1=c.biancheng.net$n #字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析
str2="shell \"script\" $n" #字符串中可以出现双引号,只要它被转义了就行。
str3='C语言中文网 $n' #原样输出 ,而且单引号内不能出现单引号
echo $str1
echo $str2
echo $str3
运行结果:
c.biancheng.net74
shell "script" 74
C语言中文网 $n
str1 中包含了$n
,它被解析为变量 n 的引用。$n
后边有空格,紧随空格的是 str2;Shell 将 str2 解释为一个新的变量名,而不是作为字符串 str1 的一部分。
str2 中包含了引号,但是被转义了(由反斜杠\
开头的表示转义字符)。str2 中也包含了$n
,它也被解析为变量 n 的引用。
str3 中也包含了$n
,但是仅仅是作为普通字符,并没有解析为变量 n 的引用。
字符串拼接
然而,在 Shell 中你不需要使用任何运算符,将两个字符串并排放在一起就能实现拼接,非常简单粗暴。请看下面的例子:
#!/bin/bash
name="Shell"
url="http://c.biancheng.net/shell/"
str1=$name$url #中间不能有空格
str2="$name $url" #如果被双引号包围,那么中间可以有空格
str3=$name": "$url #中间可以出现别的字符串
str4="$name: $url" #这样写也可以
str5="${name}Script: ${url}index.html" #这个时候需要给变量名加上大括号
echo $str1
echo $str2
echo $str3
echo $str4
echo $str5
运行结果:
Shellhttp://c.biancheng.net/shell/
Shell http://c.biancheng.net/shell/
Shell: http://c.biancheng.net/shell/
Shell: http://c.biancheng.net/shell/
ShellScript: http://c.biancheng.net/shell/index.html
字符串的截取
格式 | 说明 |
---|---|
${string: start} | 从 string 字符串的左边第 start 个字符开始截取,直到最后。 url=“c.biancheng.net” echo ${url: 2} #结果为biancheng.net。 |
${string: start :length} | 从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。索引从0开始 url=“c.biancheng.net” echo ${url: 2: 9} #结果为 biancheng 。 |
${string: 0-start :length} | 从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。 url="c.biancheng.net" echo ${url: 0-13: 9} #结果为 biancheng 。从右边数,b 是第 13 个字符。 |
${string: 0-start} | 从 string 字符串的右边第 start 个字符开始截取,直到最后。后面数就从一开始数 url=“c.biancheng.net” echo ${url: 0-13} #省略 length,直接截取到字符串末尾 结果为 biancheng.net 。 |
${string#*chars} | 从 string 字符串第一次出现 *chars 的位置开始,截取 chars 右边的所有字符。 url="http://c.biancheng.net/index.html" echo ${url#:} #结果为 //c.biancheng.net/index.htm |
${string##*chars} | 从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。 |
${string%*chars} | 从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。 |
${string%%*chars} | 从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。 |
${string##*chars}从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
1. \#!/bin/bash
2.
3. url="http://c.biancheng.net/index.html"
4. echo ${url#*/} #结果为 /c.biancheng.net/index.html
5. echo ${url##*/} #结果为 index.html
6.
7. str="---aa+++aa@@@"
8. echo ${str#*aa} #结果为 +++aa@@@
9. echo ${str##*aa} #结果为 @@@
使用 % 截取左边字符
请注意*的位置,因为要截取 chars 左边的字符,而忽略 chars 右边的字符,所以*应该位于 chars 的右侧。其他方面%和#的用法相同,这里不再赘述,仅举例说明:
#!/bin/bash
url="http://c.biancheng.net/index.html"
echo ${url%/*} #结果为 http://c.biancheng.net
echo ${url%%/*} #结果为 http:
str="---aa+++aa@@@"
echo ${str%aa*} #结果为 ---aa+++
echo ${str%%aa*} #结果为 ---
1) 从字符串左边开始计数
如果想从字符串的左边开始计数,那么截取字符串的具体格式如下:
${string: start :length}
其中,string 是要截取的字符串,start 是起始位置(从左边开始,从 0 开始计数),
length 是要截取的长度(省略的话表示直到字符串的末尾)。
例如:
url="c.biancheng.net"
echo ${url: 2: 9} #结果为`biancheng`。url="http://c.biancheng.net/index.html"
echo ${url#*/} #结果为 /c.biancheng.net/index.html
echo ${url##*/} #结果为 index.html
2) 从右边开始计数
如果想从字符串的右边开始计数,那么截取字符串的具体格式如下:
${string: 0-start :length}
同第 1) 种格式相比,第 2) 种格式仅仅多了0-
,这是固定的写法,专门用来表示从字符串右边开始计数。
这里需要强调两点:
- 从左边开始计数时,起始数字是 0(这符合程序员思维);从右边开始计数时,起始数字是 1(这符合常人思维)。计数方向不同,起始数字也不同。
- 不管从哪边开始计数,截取方向都是从左到右。
例如:
url="c.biancheng.net"
echo ${url: 0-13: 9}
结果为biancheng
。从右边数,b
是第 13 个字符。
再如:
url="c.biancheng.net"
echo ${url: 0-13} #省略 length,直接截取到字符串末尾
结果为biancheng.net
。
Shell alias:给命令创建别名
alisa 用来给命令创建一个别名。若直接输入该命令且不带任何参数,则列出当前 Shell 进程中使用了哪些别名。现在你应该能理解类似ll
这样的命令为什么与ls -l
的效果是一样的吧。
下面让我们来看一下有哪些命令被默认创建了别名:
[mozhiyan@localhost ~]$ alias
alias cp='cp -i'
alias l.='ls -d .* --color=tty'
alias ll='ls -l --color=tty'
alias ls='ls --color=tty'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
alias new_name='command'
比如,一般的关机命令是shutdown-h now,写起来比较长,这时可以重新定义一个关机命令,以后就方便多了。
alias myShutdown='shutdown -h now'
再如,通过 date 命令可以获得当前的 UNIX 时间戳,具体写法为date +%s,如果你嫌弃它太长或者不容易记住,那可以给它定义一个别名。
alias timestamp='date +%s'
Shell read命令:读取从键盘输入的数据
a array | 把读取的数据赋值给数组 array,从下标 0 开始。 |
---|---|
-d delimiter | 用字符串 delimiter 指定读取结束的位置,而不是一个换行符(读取到的数据不包括 delimiter)。 |
-e | 在获取用户输入的时候,对功能键进行编码转换,不会直接显式功能键对应的字符。 |
-n num | 读取 num 个字符,而不是整行字符。 |
-p prompt | 显示提示信息,提示内容为 prompt。 |
-r | 原样读取(Raw mode),不把反斜杠字符解释为转义字符。 |
-s | 静默模式(Silent mode),不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这是很有必要的。 |
-t seconds | 设置超时时间,单位为秒。如果用户没有在指定时间内输入完成,那么 read 将会返回一个非 0 的退出状态,表示读取失败。 |
-u fd | 使用文件描述符 fd 作为输入源,而不是标准输入,类似于重定向。 |
【实例1】使用 read 命令给多个变量赋值。
#!/bin/bash
read -p "Enter some information > " name url age #-p prompt显示提示信息,提示内容为 prompt。
echo "网站名字:$name"
echo "网址:$url"
echo "年龄:$age"
运行结果:
Enter some information > C语言中文网 http://c.biancheng.net 7↙
网站名字:C语言中文网
网址:http://c.biancheng.net
年龄:7
read -n 1 -p "Enter a char > " char
printf "\n" #换行
echo $char
运行结果:
Enter a char > 1
1
-n 1表示只读取一个字符。运行脚本后,只要用户输入一个字符,立即读取结束,不用等待用户按下回车键。
在指定时间内输入密码。
#!/bin/bash
if
read -t 20 -sp "Enter password in 20 seconds(once) > " pass1 && printf "\n" && #第一次输入密码
read -t 20 -sp "Enter password in 20 seconds(again)> " pass2 && printf "\n" && #第二次输入密码
[ $pass1 == $pass2 ] #判断两次输入的密码是否相等
then
echo "Valid password"
else
echo "Invalid password"
fi
这段代码中,我们使用&&
组合了多个命令,这些命令会依次执行,并且从整体上作为 if 语句的判断条件,只要其中一个命令执行失败(退出状态为非 0 值),整个判断条件就失败了,后续的命令也就没有必要执行了。
如果两次输入密码相同,运行结果为:
Enter password in 20 seconds(once) >
Enter password in 20 seconds(again)>
Valid password
如果两次输入密码不同,运行结果为:
Enter password in 20 seconds(once) >
Enter password in 20 seconds(again)>
Invalid password
如果第一次输入超时,运行结果为:
Enter password in 20 seconds(once) > Invalid password
如果第二次输入超时,运行结果为:
Enter password in 20 seconds(once) >
Enter password in 20 seconds(again)> Invalid password
Shell (()):对整数进行数学运算
let语法和(())比较和区别
let命令和(())的语法类似:
echo let a+b #错误,echo会把 let a+b作为一个字符串输出 只能这样:echo((a+b))
i=2
echo let i+=8 #结果:10
Shell (( )) 的用法
双小括号 (( )) 的语法格式为:
((表达式))
通俗地讲,就是将数学运算表达式放在((
和))
之间。
表达式可以只有一个,也可以有多个,多个表达式之间以逗号,
分隔。对于多个表达式的情况,以最后一个表达式的值作为整个 (( )) 命令的执行结果。
可以使用$
获取 (( )) 命令的结果,这和使用$
获得变量值是类似的。
运算操作符/运算命令 | 说明 |
---|---|
((a=10+66) ((b=a-15)) ((c=a+b)) | 这种写法可以在计算完成后给变量赋值。以 ((b=a-15)) 为例,即将 a-15 的运算结果赋值给变量 c。 注意,使用变量时不用加$ 前缀,(( )) 会自动解析变量名。 |
a= ( ( 10 + 66 ) b = ((10+66) b= ((10+66)b=((a-15)) c=$((a+b)) | 可以在 (( )) 前面加上$ 符号获取 (( )) 命令的执行结果,也即获取整个表达式的值。以 c=
(
(
a
+
b
)
)
为
例
,
即
将
a
+
b
这
个
表
达
式
的
运
算
结
果
赋
值
给
变
量
c
。
注
意
,
类
似
c
=
(
(
a
+
b
)
)
这
样
的
写
法
是
错
误
的
,
不
加
‘
((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。 注意,类似 c=((a+b)) 这样的写法是错误的,不加`
((a+b))为例,即将a+b这个表达式的运算结果赋值给变量c。注意,类似c=((a+b))这样的写法是错误的,不加‘`就不能取得表达式的结果。 |
((a>7 && b==c)) | (( )) 也可以进行逻辑运算,在 if 语句中常会使用逻辑运算。 |
echo $((a+10)) | 需要立即输出表达式的运算结果时,可以在 (( )) 前面加$ 符号。 |
((a=3+5, b=a+10)) | 对多个表达式同时进行计算。 |
在 (( )) 中使用变量无需加上$
前缀,(( )) 会自动解析变量名,这使得代码更加简洁,也符合程序员的书写习惯。
Shell (( )) 实例演示
【实例1】利用 (( )) 进行简单的数值计算。
[c.biancheng.net]$ echo $((1+1))
2
[c.biancheng.net]$ echo $((6-3))
3
[c.biancheng.net]$ i=5
[c.biancheng.net]$ ((i=i*2)) #可以简写为 ((i*=2))。
[c.biancheng.net]$ echo $i #使用 echo 输出变量结果时要加 $。
10
【实例2】用 (( )) 进行稍微复杂一些的综合算术运算。
[c.biancheng.net]$ ((a=1+2**3-4%3))
[c.biancheng.net]$ echo $a
8
[c.biancheng.net]$ b=$((1+2**3-4%3)) #运算后将结果赋值给变量,变量放在了括号的外面。
[c.biancheng.net]$ echo $b
8
[c.biancheng.net]$ echo $((1+2**3-4%3)) #也可以直接将表达式的结果输出,注意不要丢掉 $ 符号。
8
[c.biancheng.net]$ a=$((100*(100+1)/2)) #利用公式计算1+2+3+...+100的和。
[c.biancheng.net]$ echo $a
5050
[c.biancheng.net]$ echo $((100*(100+1)/2)) #也可以直接输出表达式的结果。
5050
【实例3】利用 (( )) 进行逻辑运算。
[c.biancheng.net]$ echo $((3<8)) #3<8 的结果是成立的,因此,输出了 1,1 表示真
1
[c.biancheng.net]$ echo $((8<3)) #8<3 的结果是不成立的,因此,输出了 0,0 表示假。
0
[c.biancheng.net]$ echo $((8==8)) #判断是否相等。
1
[c.biancheng.net]$ if ((8>7&&5==5))
> then
> echo yes
> fi
yes
最后是一个简单的 if 语句的格式,它的意思是,如果 8>7 成立,并且 5==5 成立,那么输出 yes。显然,这两个条件都是成立的,所以输出了 yes。
【实例4】利用 (( )) 进行自增(++)和自减(–)运算。
[c.biancheng.net]$ a=10
[c.biancheng.net]$ echo $((a++)) #如果++在a的后面,那么在输出整个表达式时,会输出a的值,因为a为10,所以表达式的值为10。
10
[c.biancheng.net]$ echo $a #执行上面的表达式后,因为有a++,因此a会自增1,因此输出a的值为11。
11
[c.biancheng.net]$ a=11
[c.biancheng.net]$ echo $((a--)) #如果--在a的后面,那么在输出整个表达式时,会输出a的值,因为a为11,所以表达式的值的为11。
11
[c.biancheng.net]$ echo $a #执行上面的表达式后,因为有a--,因此a会自动减1,因此a为10。
10
[c.biancheng.net]$ a=10
[c.biancheng.net]$ echo $((--a)) #如果--在a的前面,那么在输出整个表达式时,先进行自增或自减计算,因为a为10,且要自减,所以表达式的值为9。
9
[c.biancheng.net]$ echo $a #执行上面的表达式后,a自减1,因此a为9。
9
[c.biancheng.net]$ echo $((++a)) #如果++在a的前面,输出整个表达式时,先进行自增或自减计算,因为a为9,且要自增1,所以输出10。
10
[c.biancheng.net]$ echo $a #执行上面的表达式后,a自增1,因此a为10。
10
本教程假设读者具备基本的编程能力,相信读者对于前自增(前自减)和后自增(后自减)的区别也非常清楚,这里就不再赘述,只进行简单的说明:
- 执行 echo $((a++)) 和 echo $((a–)) 命令输出整个表达式时,输出的值即为 a 的值,表达式执行完毕后,会再对 a 进行 ++、-- 的运算;
- 而执行 echo $((++a)) 和 echo $((–a)) 命令输出整个表达式时,会先对 a 进行 ++、-- 的运算,然后再输出表达式的值,即为 a 运算后的值。
【实例5】利用 (( )) 同时对多个表达式进行计算。
[c.biancheng.net]$ ((a=3+5, b=a+10)) #先计算第一个表达式,再计算第二个表达式
[c.biancheng.net]$ echo $a $b
8 18
[c.biancheng.net]$ c=$((4+8, a+b)) #以最后一个表达式的结果作为整个(())命令的执行结果
[c.biancheng.net]$ echo $c
26
学习目标:
提示:这里可以添加学习目标
例如:一周掌握 Java 入门知识
学习内容:
提示:这里可以添加要学的内容
例如:
1、 搭建 Java 开发环境
2、 掌握 Java 基本语法
3、 掌握条件语句
4、 掌握循环语句
学习时间:
提示:这里可以添加计划学习的时间
例如:
1、 周一至周五晚上 7 点—晚上9点
2、 周六上午 9 点-上午 11 点
3、 周日下午 3 点-下午 6 点
学习产出:
提示:这里统计学习计划的总量
例如:
1、 技术笔记 2 遍
2、CSDN 技术博客 3 篇
3、 学习的 vlog 视频 1 个