一、基本语法
1. 执行shell脚本
- 通过bash解析器执行,可以直接运行
.sh
文件
sh hello.sh #相对路径
sh /home/hello.sh #绝对路径
bash hello.sh
bash /home/hello.sh
- 通过脚本自己执行,需要执行权限
chmod +x hello.sh #需要先给shell文件加执行权限
./hello.sh #直接调用
/home/hello.sh
2. 变量
2.1 普通变量
A=abc # 局部变量
export B=20 # 全局变量
readonly C=30 #静态变量
unset A #撤销变量,静态变量不可撤销
Str="hello world" #若变量值中有空格,需要双/单引号
s=$[1+2+3] #运算
2.2 特殊变量
$0, $1, $2
代表执行脚本时,输入的参数。$0
代表脚本名称
$#
:代表输入的参数个数
$*
,$@
:代表所有传入的参数,$*
将参数看作整体,$@
看作每个独立的参数
$?
:查看上次脚本的执行状态,返回0正常,否则不正常
#!/bin/bash
echo $0, $1, $2
echo $#
echo $*
echo $@
./hello.sh 1 abc
echo $?
3. 基本语法
3.1 条件判断
判断条件
[ condition ] 对[ ]
内的条件进行判断,注意condition前后有空格,条件非空即为true,[ atguigu ]返回true,[] 返回false。
- 两个整数之间比较
-lt 小于(less than) -le 小于等于(less equal)
-eq 等于(equal) -gt 大于(greater than)
-ge 大于等于(greater equal) -ne 不等于(Not equal)
[ 22 ge 23 ]
echo $?
- 判断文件权限
-r 有读的权限(read) -w 有写的权限(write)
-x 有执行的权限(execute)
[ -w hello.sh ]
$?
- 判断文件存在
-f 文件存在并且是一个常规的文件(file)
-e 文件存在(existence) -d 文件存在并是一个目录(directory)
[ -e hello.sh ]
$?
- 多条件判断:
&&
、||
[ conditon ] && echo ok || echo notok
[ ] && echo ok || echo notok
判断语法
if …else
if [ $1 -le 10 ] #条件判断 注意if后有空格
then
$echo 9
elif [ $1 -le 100 ]
then
$echo 99
else
echo 999
fi #结束判断
switch …case
switch $1 in
10)
echo 9
;; #相当于break
100)
echo 99
;;
*) #相当于default
echo 999
;;
esac #结束
3.2 流程控制
for循环
for ((循环条件))
s=0
for ((i=0;i<10;i++))
do
s=$[$s+$i]
echo $s
done
for … in
$*
和$@
的区别: 当无双引号时,会逐条循环,若有双引号时,$*
会看做一个整体支循环一次
for i in "$*"
do
echo $i
done
for i in $@
do
echo $i
done
while循环
i=0
s=0
while [ i -le 10 ]
do
s=$[$s+$i]
i=$[$i+1]
done
3.3 read语法
read(选项)(参数)
选项:
-p:指定读取值时的提示符;
-t:指定读取值时等待的时间(秒)。
参数:指定读取值的变量名
#!/bin/bash
read -t 7 -p "input name:" name
echo $name
二、函数
1. 系统函数
basename
获取路径最后一层的名称dirname
获取当前文件的路径
basename /root/shelltest #shelltest
dirname /root/shelltest/hello.sh #/root/shelltest
2. 自定义函数
read -t 10 -p "请输入数据:" N1
read -t 5 -p "请输入第二个数据:" N2
total=0
function func() {
total=$[$1+$2]
# return total #返回值最大为int型的255,超过255返回与256取余的值
}
func $N1 $N2
# echo "total=$?"
echo "total=$total"
3. 正则表达式
cat /etc/passwd | grep hello #直接匹配
cat /etc/passwd | grep a^ #匹配a开头的行
cat /etc/passwd | grep t$ #匹配t结尾的行
cat /etc/passwd | grep ro..t # .代表任意一个字符
cat /etc/passwd | grep ro*t # *代表前一个字符可以出现0次或任意次数
cat /etc/passwd | grep r[o,a]t # [o, a]代表可以是其中的一个
cat /etc/passwd | grep '\$' # \代表转意字符,$转意要加单引号
Shell工具
1. cut
-d 分隔符
-f 取第几行
-c 取第几个字符
# 切出第一列
cut -d " " -f 1 hello.sh
# 切出2、3列
cut -d " " -f 2,3 hello.sh
cut -d " " -f 2-3 hello.sh
# 切割第二列之后所有
cut -d " " -f 2- hello.sh
# 切出指定的单词
cat hello.sh | grep guan | cut -d " " -f 1
# 选取系统PATH变量值,第2个“:”开始后的所有路径:
echo $PATH | cut -d ":" -f 3-
# 切割ifconfig 后打印的IP地址
ifconfig | grep netmask | cut -d "i" -f 2 | cut -d " " -f 2
2. awk
-F 指定分隔符
-v 自定义变量
FILENAME 文件名
NR 已读的记录数(行数)
NF 浏览记录的域的个数(切割后,列的个数)
#搜索root关键字开头的所有行,并输出该行的第7列。
awk -F ":" '/root^/{print $7}' passed.txt
#搜索以root关键字开头的所有行,并输出该行以“,”号分割第1列和第7列。
awk -F ":" '/root^/{print $7 "," $7}' passwd.txt
#只显示/etc/passwd的第一列和第七列,且在所有行前面添加列名aaa在最后一行添加bbb
awk 'BEGIN{print "aaa"}{print $1, $7}END{print "bbb"}' passwd.txt
#将passwd文件中的用户id增加数值1并输出
awk -v i=1 -F ":" 'print{$3+i}' passwd.txt
#统计passwd文件名,每行的行号,每行的列数
awk '{print "filename:" FILENAM, "行号: " NR, "列数:" NF}' passwd.txt
#切割IP
ifconfig | grep netmask | awk -F "inet " '{print $2}' | awk -F " " '{print $1}'
#查询cut.txt中空行所在的行号
awk '/^$/{print NR}' hello.sh
3. sort
-n 依照数值的大小排序
-r 以相反的顺序来排序
-t 设置排序时所用的分隔字符
-k 指定需要排序的列
# 按照第三列数字倒序
sort -t ":" -nrk 3 shell.sh
综合示例:分发hadoop文件
#!/bin/bash
if [ $# -lt 1 ]
then
echo "为输入传输文件"
exit
fi
for file in $@
do
if [ -e $file ]
then
for host in hadoop103 hadoop104
do
#获取文件i路径
filepath=$(cd -P $(dirname $file); pwd)
filename=$(basename $file)
#创建远程路径
ssh $host "mkdir -p $filepath"
#传送数据
rsync -av $filepath/$filename $host:$filepath/
done
else
echo "$file 不存在"
fi
done