Shell 简介
Shell 首先是 UNIX/Linux 下的脚本编程语言,它是解释执行的,无需提前编译。Shell 的语法细节和你熟悉的大部分编程语言都不太一样,需要重点学习。
Shell 同时也是一个程序,它的一端连接着 UNIX/Linux 内核,另一端连接着用户和其它应用程序;换句话说,Shell 是用户和应用程序与内核沟通的桥梁。
第一个Shell脚本
创建Shell脚本文件
touch 1-first.sh
编辑文件
vi 1-first.sh
#!/bin/bash
echo "Hello World !"
修改权限(使脚本具有执行权限)
chmod 775 1-first.sh
运行脚本
./1-first.sh
变量名不加美元符号($,PHP语言中变量需要),如:
your_name="KissedBySnow"
注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
#变量赋值(可以多次赋值)
variable="aaa"
#删除变量
unset variable
#定义只读变量,只读变量不可修改,不可删除
variable="bbb"
readonly variable
name="Troy"
# 使用单引号拼接(单引号里的字符都会原样输出,即便是变量也是无效的)
a1='hello, '$name' !' #输出 hello, Troy !
a2='hello, ${name} !' #输出 hello, ${name} !
echo $a1 $a2
# 使用双引号拼接(双引号里可以有变量)
b1="hello, "$name" !" #输出 hello, Troy !
b2="hello, ${name} !" #输出 hello, Troy !
echo $b1 $b2
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
注意: 以上脚本中 ` 是反引号,而不是单引号 '。
bash仅支持一维数组,不限定数组大小。数组元素的下标由0开始。
Shell中,使用括号来表示数组,数组元素用“空格”符号分隔开。定义数组的一般形式为:
数组名=(值1 值2 ... 值n)
例如:
array=(value0 value1 value2 value3 value4)
或者
array=(
value0
value1
value2
value3
)
还可以单独定义数组的各个分量:
array[0]=value0
array[1]=value1
可以不使用连续的下标,而且下标的范围没有限制。
读取数组元素值的一般格式是:
${数组名[下标]}
例如:
aaa=${array_name[2]}
使用 @ 符可以获取数组中的所有元素,例如:
echo ${array_name[@]}
echo ${array_name[*]} # *符也可以
获取数组长度的方法与获取字符串长度的方法相同,例如:
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}
单行注释
以 # 开头的行就是注释,会被解释器忽略。
多行注释
:<<EOF
注释内容...
注释内容...
注释内容...
EOF
# EOF 也可以使用其他符号代替:
:<<'
注释内容...
注释内容...
注释内容...
'
:<<!
注释内容...
注释内容...
注释内容...
!
实例1:实现两个数的相加
touch addition.sh
vi addition.sh
#!/bin/bash
echo `expr $1 + $2` #这是一个加法公式,传入两个参数并相加后,输出。输出结果:3
echo $0 #输出执行的文件名
chmod 770 addition.sh
./addition.sh 1 2
输出结果:
3
./addition.sh
#!/bin/bash
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";
echo "传递的参数作为多个字符串显示:$@";
[yzy@localhost shell练习区]$ ./3.sh 99 88 77
Shell 传递参数实例!
执行的文件名:./3.sh
第一个参数为:99
第二个参数为:88
第三个参数为:77
参数个数为:3
传递的参数作为一个字符串显示:99 88 77
传递的参数作为多个字符串显示:99 88 77
$* 与 $@ 区别:
#!/bin/bash
echo "-- \$* 演示 ---"
for i in "$*"; do
echo $i
done
echo "-- \$@ 演示 ---"
for i in "$@"; do
echo $i
done
[yzy@localhost shell练习区]$ ./4.sh 99 88 77
-- $* 演示 ---
99 88 77
-- $@ 演示 ---
99
88
77
$ echo $[1+2]
3
$ echo `expr 1 + 2`
3
$[1+2] 等价于 `expr 1 + 2`
下表列出了常用的算术运算符,假定 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 |
注意1: 条件表达式要放在方括号之间,并且要有空格。例如:
[$a==$b] 是错误的
[ $a == $b ] 是正确的
注意2:
乘号(*)前边必须加反斜杠(\)才能实现乘法运算;
实例:
#!/bin/bash
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
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| | 逻辑的 OR | [[ $a -lt 100 || $b -gt 100 ]] 返回 true |
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 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。 |
文件测试运算符用于检测 Unix 文件的各种属性。
操作符 | 说明 | 举例 |
---|---|---|
-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。 |
#!/bin/bash
file="/home/yzy/shell练习区/1-first.sh"
if [ -r $file ]
then
echo "文件可读"
else
echo "文件不可读"
fi
if [ -w $file ]
then
echo "文件可写"
else
echo "文件不可写"
fi
if [ -x $file ]
then
echo "文件可执行"
else
echo "文件不可执行"
fi
if [ -f $file ]
then
echo "文件为普通文件"
else
echo "文件为特殊文件"
fi
if [ -d $file ]
then
echo "文件是个目录"
else
echo "文件不是个目录"
fi
if [ -s $file ]
then
echo "文件不为空"
else
echo "文件为空"
fi
if [ -e $file ]
then
echo "文件存在"
else
echo "文件不存在"
fi
[yzy@localhost shell练习区]$ ./5-fifth
文件可读
文件可写
文件可执行
文件为普通文件
文件不是个目录
文件不为空
文件存在
1.显示普通字符串:
echo "It is a test"
这里的双引号完全可以省略,以下命令与上面实例效果一致:
echo It is a test
2.显示转义字符
echo "\"It is a test\""
echo \"It is a test\"
结果将是:
"It is a test"
"It is a test"
3.显示变量
read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量
#!/bin/sh
read name
echo "$name It is a test"
以上代码保存为 test.sh,name 接收标准输入的变量,结果将是:
[root@www ~]# sh test.sh
OK #标准输入
OK It is a test #输出
4.显示换行
echo -e "OK! \n" # -e 开启转义
echo "It is a test"
输出结果:
OK!
It is a test
5.显示不换行
#!/bin/sh
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"
输出结果:
OK! It is a test
6.显示结果定向至文件
echo "It is a test" > myfile
7.原样输出字符串,不进行转义或取变量(用单引号)
echo '$name\"'
输出结果:
$name\"
8.显示命令执行结果
echo `date`
注意: 这里使用的是反引号 `, 而不是单引号 '。
结果将显示当前日期
2019年 04月 23日 星期二 22:05:50 CST
printf 命令格式:
printf "类型+格式" 输出内容
english | 输出类型 | 解释 |
---|---|---|
Char | %c | 字符 |
String | %s | 字符串 |
Decimal | %d | 十进制整数 |
Integer | %i | 整数 |
Float | %f | 浮点数 |
输出格式 | 解释 |
---|---|
\n | 换行 |
\a | 输出警告声音 |
\b | 输出退格键,也就是 Backspaced 键 |
\f | 清除屏幕 |
\r | 回车,也就是 Enter 键 |
\t | 水平输出退格键,也就是 Tab 键 |
\v | 垂直输出退格键,也就是 Tab 键 |
实例1:
#!/bin/bash
# 单引号与双引号效果一样
printf "%d %s\n" 1 "aaa"
printf '%d %s\n' 1 "aaa"
# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
printf "%s\n" c c c
printf "%i %i %i\n" 1 2 3 4 5 6 7 8 9
# 如果没有 输出内容,那么 %s 用NULL代替,%d 用 0 代替
printf "%s and %d \n"
# 没有引号也可以输出,但是换行符就不能用了
printf %s\n bbb
$ ./6-sixth.sh
1 aaa
1 aaa
c
c
c
1 2 3
4 5 6
7 8 9
and 0
bbbn
实例2:
简单调用:
[yzy@localhost shell练习区]$ printf "<%s>\t" A B C D
<A> <B> <C> <D>
实例3:
调用文件中的内容
$ vi student.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
$ printf '%2s %8s %8s %8s %8s %8s \n' $(cat student.txt)
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
去掉表头(第一行标题):
$ printf '%2i %8s %8i %8i %8i %8.2f \n' $(cat student.txt|grep -v Name)
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
https://www.runoob.com/linux/linux-shell-test.html
if condition
then
command1
command2
...
commandN
fi
if condition
then
command1
command2
...
commandN
else
command
fi
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
例,顺序输出当前列表中的数字:
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
while condition
do
command
done
while :
do
command
done
while true
do
command
done
for (( ; ; ))
until 循环执行一系列命令直至条件为 true 时停止。
until 循环与 while 循环在处理方式上刚好相反。
一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。
until condition
do
command
done
condition 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。
以下实例我们使用 until 命令来输出 0 ~ 9 的数字:
#!/bin/bash
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
输出结果为:
0
1
2
3
4
5
6
7
8
9
case 值 in
模式1)
command
;;
模式2)
command
;;
*)
command
;;
esac
注意:
下面的脚本提示输入1到4,与每一种模式进行匹配:
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
输入 1 到 4 之间的数字:
你输入的数字为:
3
你选择了 3
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
while循环将一直调用,break命令跳出case while两层循环。
输入 1 到 5 之间的数字:3
你输入的数字为 3!
输入 1 到 5 之间的数字:7
你输入的数字不是 1 到 5 之间的! 游戏结束
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 “游戏结束” 永远不会被执行。
https://www.runoob.com/linux/linux-shell-func.html
函数返回值在调用该函数后通过 $? 来获得
https://www.runoob.com/linux/linux-shell-io-redirections.html
shell可以包含外部脚本,这样可以很方便的封装一些独立的代码文件。
语法格式:
. fileName #注意点号.和文件名之间有一个空格
或者
source fileName
实例: 创建两个shell脚本
test1.sh
#!/bin/bash
url="blog.csdn.net/KissedBySnow/"
test2.sh
#!/bin/bash
. ./test1.sh #使用.来引用test1.sh
echo "地址:$url"
接下来,我们为 test2.sh 添加可执行权限并执行:
$ chmod +x test2.sh
$ ./test2.sh
地址:blog.csdn.net/KissedBySnow/