@[toc]
Shell脚本入门
(1) 脚本格式:
脚本以 #!/bin/bash
开头(指定解释器)
练习:
创建一个Shell脚本,输出 hello world
PS:vim功能很强大,如果有文件就直接打开,如果没文件就创建并打开。
终端输入:
[root@hadoop100 scripts]# vim hello.sh
按i进入编辑模式,文件里输入:
#!/bin/bash
echo "hello world"
按Esc退出编辑模式,按 :wq
保存并退出。
(2) 脚本执行:
- 第一种:采用
bash
或sh
+脚本的相对路径或绝对路径 (不用赋予脚本 +x 权限)
bash+脚本的相对路径:
[root@hadoop100 scripts]# bash hello.sh
hello,world
bash+脚本的绝对路径:
[root@hadoop100 scripts]# bash /root/scripts/hello.sh
hello,world
sh+脚本的相对路径:
[root@hadoop100 scripts]# sh hello.sh
hello,world
sh+脚本的绝对路径:
[root@hadoop100 scripts]# sh /root/scripts/hello.sh
hello,world
- 第二种:直接输入脚本的绝对路径或相对路径(必须赋予脚本
+x
可执行权限)
PS:r是读权限,w是写权限,x是可执行权限。一般刚创建的文件只有rw权限,没有x权限,x权限那里是个 -
①首先要赋予脚本 +x 权限
[root@hadoop100 scripts]# chmod +x hello.sh
②执行脚本
相对路径
[root@hadoop100 scripts]# ./hello.sh
hello,world
绝对路径:
[root@hadoop100 scripts]# /root/scripts/hello.sh
hello,world
知识拓展:
- 这两种方法都是在当前 shell 中打开一个子 shell 来执行脚本内容,当脚本内容结束,则子 shell关闭,回到父 shell 中。(存在环境变量继承问题:如在子 shell 中设置的当前变量,父 shell 是不可见的)
- 第一种执行方法本质是bash解析器执行脚本,所以脚本本身不需要执行权限。第二种执行方法本质是脚本需要自己执行,所以需要执行权限。
- pwd 查看目录 ; mkdir 创建文件夹 ; touch 新建文件 ; cat 查看内容
变量
一、系统预定义变量
(1) 常用的系统变量:
$HOME(当前主目录)、$PWD(当前工作目录目录)、$SHELL(当前使用的shell解析器)、$USER(当前用户)等。
(2) 练习:
[root@hadoop100 scripts]# echo $HOME
/root
[root@hadoop100 scripts]# echo $PWD
/root/scripts
[root@hadoop100 scripts]# echo $SHELL
/bin/bash
[root@hadoop100 scripts]# echo $USER
root
[root@hadoop100 scripts]# ls $HOME
initial-setup-ks.cfg scripts 公共 模板 视频 图片 文档 下载 音乐 桌面
二、自定义变量
(1) 基本语法:
- 定义变量: 变量名=变量值 (注意:=号前后都不能有空格!!!)
- 撤销变量: unset 变量名
- 声明静态变量: readonly 变量 (注意:不能 unset)
- 声明全局变量: export 变量
(2) 变量定义规则:
- 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
- = 等号两侧不能有空格。
- 在 bash 中,变量默认类型都是字符串类型,无法直接进行数值运算。
- 变量的值如果有空格,需要使用双引号或单引号括起来。
(3) 练习:
[root@hadoop100 scripts]# a=10
[root@hadoop100 scripts]# echo $a
10
[root@hadoop100 scripts]# unset a
[root@hadoop100 scripts]# echo $a
unset后,echo就打印空白一行了。
三、特殊变量
1、 $n
(1) 基本语法:
$n —— 位置参数
功能描述:n 为数字,$0 代表该脚本的名称,$1-$9 代表第一到第九个参数,十以上的参数需要用大括号包含,如 ${10} 。
(2) 练习:
!#/bin/bash
echo '=================$n==================='
echo script name: $0
echo 1st parameter: $1
echo 2nd parameter: $2
[root@hadoop100 scripts]# ./parameter.sh abc def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$n===================
script name: ./parameter.sh
1st parameter: abc
2nd parameter: def
2、 $
(1) 基本语法:
$# —— 参数个数统计变量
功能描述:获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及加强脚本的健壮性。
(2) 练习:
!#/bin/bash
echo '=================$n==================='
echo script name: $0
echo 1st parameter: $1
echo 2nd parameter: $2
echo '=================$#==================='
echo parameter numbers: $#
[root@hadoop100 scripts]# ./parameter.sh abc def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$n\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=
script name: ./parameter.sh
1st parameter: abc
2nd parameter: def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=
parameter numbers: 2
3、 $*、$@
(1) 基本语法:
$* —— 获取当前命令行提供的所有参数
功能描述:获取当前命令行提供的所有参数,$*把所有参数看成一个整体。
$@ —— 获取当前命令行提供的所有参数
功能描述:获取当前命令行提供的所有参数,$@把每个参数区分对待。
(2) 练习:
!#/bin/bash
echo '=================$n==================='
echo script name: $0
echo 1st parameter: $1
echo 2nd parameter: $2
echo '=================$#==================='
echo parameter numbers: $#
echo '=================$*==================='
echo $*
echo '=================$@==================='
echo $@
[root@hadoop100 scripts]# ./parameter.sh abc def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$n\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\
script name: ./parameter.sh
1st parameter: abc
2nd parameter: def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\
parameter numbers: 2
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$*===================
abc def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$@===================
abc def
区别在循环中可以看到。
4、 $?
(1) 基本语法:
$? —— 整个脚本的返回值
功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己决定,但有个范围:0~255),则证明上一个命令执行不正确了(如果用在函数里也可以表示函数的返回值,但要注意范围)。
(2) 练习:
[root@hadoop100 scripts]# ./hello.sh
hello,world
[root@hadoop100 scripts]# echo $?
0
运算符
(1) 基本语法:
$((运算式))
或 $[运算式]
(2) 练习:
[root@hadoop100 scripts]# echo $((5+2))
7
[root@hadoop100 scripts]# echo $[5*2]
10[root@hadoop100 scripts]# a=$[(2+3)*4]
[root@hadoop100 scripts]# echo $a
20
(3) 进阶练习:
编写个两数相加的文件
#!/bin/bash
sum=$[$1+$2]
echo sum=$sum
[root@hadoop100 scripts]# ./add.sh 25 90
sum=115
条件判断
(1) 基本语法:
有两种判断方法:
- test 条件判断
- [ 条件判断 ] (注意 条件判断 前后都要有空格)
PS:进行条件判断后,想看结果是真还是假,就要用 $? 接受返回值,即输入 echo $?
命令打印返回值结果。条件为真是0,条件为假是1 。
(2) 常用判断条件:
- 两个整数之间比较
符号 | 含义 |
---|---|
-eq | 等于(equal) |
-ne | 不等于(not equal) |
-lt | 小于(less than) |
-gt | 大于(greater than) |
-le | 小于等于(less equal) |
-ge | 大于等于(greater equal) |
注:如果是字符串之间的比较,用等号 = 判断相等;用 != 判断不等。
- 按照文件权限进行判断
符号 | 含义 |
---|---|
-r | 有读的权限(read) |
-w | 有写的权限(write) |
-x | 有执行的权限(execute) |
- 按照文件类型进行判断
符号 | 含义 |
---|---|
-e | 文件存在(existence) |
-f | 文件存在并且是一个常规的文件(file) |
-d | 文件存在并且是一个目录(directory) |
(3) 多条件判断:
- && :逻辑与。表示前一条命令执行成功时,才执行后一条命令。
- || :逻辑或。表示上一条命令执行失败后,才执行下一条命令。
两者结合可实现三元运算符。
(4) 练习:
[root@hadoop100 ~]# a=hello
[root@hadoop100 ~]# test $a = hello
[root@hadoop100 ~]# echo $?
0
[root@hadoop100 ~]# test $a = Hello
[root@hadoop100 ~]# echo $?
1[root@hadoop100 ~]# [ 2 -lt 8 ]
[root@hadoop100 ~]# echo $?
0
[root@hadoop100 ~]# [ 2 -gt 8 ]
[root@hadoop100 ~]# echo $?
1[root@hadoop100 ~]# cd scripts/
[root@hadoop100 scripts]# ls
add.sh cmd_test.sh fun_test.sh if_elif_else_test2.sh if_test.sh parameter.sh while_test.sh
case_test.sh for_test.sh hello.sh if_elif_else_test.sh parameter_for_test.sh read_test.sh
[root@hadoop100 scripts]# [ -x hello.sh ]
[root@hadoop100 scripts]# echo $?
0[root@hadoop100 scripts]# [ -e hello.sh ]
[root@hadoop100 scripts]# echo $?
0[root@hadoop100 scripts]# a=15
[root@hadoop100 scripts]# [ $a -lt 20 ] && echo "a比较小" || echo "a比较大"
a比较小
[root@hadoop100 scripts]# a=25
[root@hadoop100 scripts]# [ $a -lt 20 ] && echo "a比较小" || echo "a比较大"
a比较大
返回值为真,执行 || 前面的;返回值为假,执行 || 后面的。
流程控制
if 判断
(1) 基本语法:
- 单分支
if [ 条件判断式 ]
then
程序
fi
或者
if [ 条件判断式 ];then
程序
fi
- 多分支
if [ 条件判断式 ]
then
程序
elif [ 条件判断式 ]
then
程序
else
程序
fi
注意事项:
- [ 条件判断式 ],中括号和条件判断式之间必须有空格。
- if后要有空格
(2) 练习:
#!/bin/bash
if [ "$1"x = "hello"x ]
then
echo hello,world
fi
[root@hadoop100 scripts]# ./if_test.sh hello
hello,world[root@hadoop100 scripts]# echo $a
25
[root@hadoop100 scripts]# if [ $a -gt 18 ] && [ $a -lt 35 ]; then echo 青年人; fi
青年人
#!/bin/bash
if [ $1 -lt 18 ]
then
echo "未成年"
else
echo "成年了"
fi
[root@hadoop100 scripts]# ./if_test.sh 20
成年了
#!/bin/bash
if [ $1 = 1 ]
then
echo 输入了个1
elif [ $1 = 2 ]
then
echo 输入了个2
else
echo 输入的是其他
fi
[root@hadoop100 scripts]# ./if_elif_else_test.sh 2
输入了个2
#!/bin/bash
# 输入参数表示年龄,判断属于哪个年龄段
if [ $1 -lt 18 ]
then
echo 未成年人
elif [ $1 -lt 35 ]
then
echo 青年人
elif [ $1 -lt 60 ]
then
echo 中年人
else
echo 老年人
fi
[root@hadoop100 scripts]# ./if_elif_else_test2.sh 20
青年人
case 语句
(1) 基本语法:
case $变量名 in
值1)
执行程序1
;;
值2)
执行程序2
;;
......
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
注意事项:
- case行尾必须为单词
in
,每一个模式匹配必须以右括号)
结束。 - 双分号
;;
表示命令序列结束,相当于Java中的break。 - 最后的
*)
表示默认模式,相当于Java中的 default 。
(2) 练习:
#!/bin/bash
case $1 in
1)
echo one
;;
2)
echo two
;;
3)
echo three
;;
*)
echo number else
;;
esac
[root@hadoop100 scripts]# ./case_test.sh 2
two
[root@hadoop100 scripts]# ./case_test.sh 8
number else
for 循环
(1) 基本语法:
for (( 初始值;循环控制条件;变量变化))
do
程序
done
(2) 练习:
#!/bin/bash
for (( i=1;i<=$1;i++ ))
do
sum=$[ sum+i ]
done
echo $sum
[root@hadoop100 scripts]# ./for_test.sh 100
5050
(3) 基本语法2:
for 变量 in 值1 值2 值3...
do
程序
done
增强for循环
(4) 练习2:
[root@hadoop100 scripts]# for i in 哈哈 嘿嘿 呵呵; do echo $i; done
哈哈
嘿嘿
呵呵[root@hadoop100 scripts]# for i in {1..100}; do sum=$[sum+i]; done; echo $sum
5050
小tips:
- ;就代表换了一行
- {1..100} 表示生成序列,1到100的序列,用于增强for遍历
while 循环
(1) 基本语法:
while [ 条件判断式 ]
do
程序
done
(2) 练习:
#!/bin/bash
a=1
while [ $a -le $1 ]
do
# sum=$[ sum+a ] 第一种写法
# a=$[ a+1 ]
let sum+=a # 第二种写法
let a++
done
echo $sum
[root@hadoop100 scripts]# ./while_test.sh 100
5050
read 读取控制台输入
(1) 基本语法:
read (选项) (参数)
① 选项:
-p
:后跟输入时的提示句。
-t
:后跟输入时系统等待的时间(秒),如果不加 -t 则系统会一直等待。
② 参数:
变量:指定某个变量,随后运行时把值输入给它。
(2) 练习:
#!/bin/bash
read -t 10 -p "请输入名字:" name
echo Welcome,$name
如果一直不输入,10秒后,程序会自动结束
[root@hadoop100 scripts]# ./read_test.sh
请输入名字:Welcome,
如果及时输入了,则程序会正常执行
[root@hadoop100 scripts]# ./read_test.sh
请输入名字:tony
Welcome,tony
函数
一、系统函数
1、basename
(1) 基本语法:
basename [string/pathname] [suffix]
功能描述:basename 命令会删掉所有的前缀包括最后一个 / 字符,即只保留最后一个 / 之后的字符。
basename 可以理解为取路径里的文件名称。
选项:
suffix
:指定要去掉的后缀。如果 suffix 被指定了,basename 会被 pathname 或 string 中的 suffix后缀 去掉。
(2) 练习:
截取路径:
[root@hadoop100 scripts]# basename /root/scripts
scripts
还能截取普通字符串:
[root@hadoop100 scripts]# basename hdasgfua/adgdkh/dfajgk/hahaha
hahaha
加上 suffix 参数去掉指定后缀:
[root@hadoop100 scripts]# basename /root/scripts/hello.sh .sh
hello
去掉了 .sh 后缀
如果 suffix 不是后缀,则错了,不会执行此参数:
[root@hadoop100 scripts]# basename /root/scripts/hello.sh hello
hello.sh
不能去掉 hello 留 .sh ,因为 hello 不是后缀。
2、dirname
(1) 基本语法:
direname string/pathname
功能描述:对于pathname,从给定的包含绝对路径的文件名中去除文件名(非目录部分),然后返回剩下的路径(目录部分);对于字符串,删掉后缀包括最后一个 / 字符,即只保留最后一个 / 之前的字符。
dirname 可以理解为取文件路径的绝对路径名称。
(2) 练习:
截取路径:
[root@hadoop100 scripts]# dirname /root/scripts/hello.sh
/root/scripts
还能截取普通字符串:
[root@hadoop100 scripts]# dirname /hello/java/hadoop/world
/hello/java/hadoop
二、自定义函数
(1) 基本语法:
function 函数名()
{
程序;
return int;
}
简化版:
函数名()
{
程序;
}
function、return 返回值都可以选写。
(2) 经验技巧:
- 必须在调用函数地方之前,先声明函数,shell 脚本是逐行运行。不会像其他语言一样先编译。
- 函数返回值,只能通过 $? 系统变量获得,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。return 后跟数值 n(0-255)
(3) 练习:
#!/bin/bash
function add(){
s=$[$1+$2]
echo "两数之和为:"$s
}
read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b
add $a $b
[root@hadoop100 scripts]# ./fun_test.sh
请输入第一个整数:35
请输入第二个整数:25
两数之和为:60
改进版:
函数中最后用 echo 模拟返回函数的返回值。
#!/bin/bash
function add(){
s=$[$1+$2]
echo $s
}
read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b
sum=$(add $a $b)
echo "两数之和为:"$sum
文本处理工具
cut
cut 的工作就是 “剪”,具体地说就是在文件中负责剪切数据用的。cut 命令从文件的每一行剪切字节、字符和字段,并将这些字节、字符和字段输出。
(1) 基本用法:
cut [选项参数] filename
说明:默认分隔符是制表符 \t
(2) 选项参数说明:
-f
:列号。提取第几列
-d
:分隔符。按照指定分隔符分割列,默认是制表符 \t
-c
:按字符进行切割,后加数字,表示取第几列。比如 -c 2
(3) 练习:
查看要用的数据
[root@hadoop100 scripts]# cat cut.txt
dong shen he
guan zhen nan
wo wo wo
lai lai lai
le le le
切割 cut.txt 第一列
[root@hadoop100 scripts]# cut -d " " -f 1 cut.txt
dong
guan
wo
lai
le
切割 cut.txt 第二、三列
[root@hadoop100 scripts]# cut -d " " -f 2,3 cut.txt
shen he
zhen nan
wo
lai
le
在 cut.txt 文件中切割出 guan
这能截取一行
[root@hadoop100 scripts]# cat cut.txt | grep guan
guan zhen nan
这一行中再切第一列
[root@hadoop100 scripts]# cat cut.txt | grep guan | cut -d " " -f 1
guan
awk
一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
(1) 基本用法:
awk [选项参数] '/pattern1/{action1} /pattern2/{action2}...' filename
pattern:表示 awk 在数据中查找的内容,就是匹配模式
action :在找到匹配内容时所执行的一系列命令
(2) 选项参数说明:
-F
:指定输入文件的分隔符
-v
:赋值一个用户定义变量
(3) 练习:
搜索 passwd 文件以 root 关键字开头的所有行,并输出该行的第7列
[root@hadoop100 scripts]# cat /etc/passwd | grep ^root | cut -d ":" -f 7
/bin/bash
[root@hadoop100 scripts]# cat /etc/passwd | awk -F ":" '/^root/ {print $7}'
/bin/bash
搜索 passwd 文件以 root 关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”分割。
[root@hadoop100 scripts]# cat /etc/passwd | awk -F ":" '/^root/ {print $1","$7}'
root,/bin/bash