入门
Shell是一个命令行解释器,接收到程序或用户的命令,然后调用操作系统内核。可撰写比较复杂的流程,一个易编写、易调试、灵活性强的编程语言。
# cat /etc/shells(查看支持的shell文件
Redhat默认bash,ubuntu默认dash。
#ls -l /bin/ | grep bash查看默认的版本
可以看到很多都基于bash
#注释
#!/bin/sh指定解释器,但是sh指向bash
[atguigu@hadoop101 shells]$ touch helloworld.sh
[atguigu@hadoop101 shells]$ vim helloworld.sh
在 helloworld.sh 中输入如下内容
#!/bin/bash
echo "helloworld"
脚本的常用执行方式
第一种:采用 bash 或 sh+脚本的相对路径或绝对路径(不用赋予脚本+x 权限)
第二种:采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x)
【了解】第三种:在脚本的路径前加上“.”或者 source
#第一种
bash ./helloworld.sh
bash /root/scripts/hello.sh(绝对路径)
bash scripts/hello.sh(相对路径)
#第二种,注意权限。读(w)写(r)可执行(x)
chmod +x scripts/hello.sh(加权限
ll scripts/(查权限
直接
/root/scripts/hello.sh(绝对路径执行)
bash scripts/hello.sh(相对路径执行)
但直接
hello.sh(不能执行,因为默认它是命令)
可以直接
./helloworld.sh(最常用)
第三种
source hello.sh
source
. hello.sh
. /root/scripts/hello.sh
第一种相当于启用了bash进程,属于传参,但是第二种直接让环境执行所以需要权限。第三种.是命令,第二种.是当前目录的意思。
ps -l(查看进程,发现子shell
第三种与前两种的区别,开子 shell 与不开子 shell 的区别就在于,环境变量的继承关系,如在子 shell 中设置的当前变量,父 shell 是不可见的。
变量
系统变量+用户变量,全局变量+局部变量
常用系统变量:$HOME、$PWD、$SHELL、$USER等。
env | less
printenv | less
printenv USER
echo $USER(当变量
ls $HOME
export my_var(导出,即设为全局变量,不需要$符号
ps -f(查看cmd,-bash,bash
unset a
Shell的变量不是静态的,或者说不细分,不需要声明数据类型。千万不能加空格!千万不能加空格 !千万不能加空格!
子shell修改不影响父shell
自定义变量一般用小写,环境变量大写
默认为String,想做数值运算需要$[]或者$(()),readonly是只读变量,unset可设置可撤销,常量(只读变量)不可unset
变量名不能以数字开头
$1,执行加参数
单引号不会误认为是变量。
basename获取本身的名称,不获取路径。
echo $#获取当前参数个数,$*所有参数视为一个整体,$@一个数组,可用for循环遍历。
运算符
expr表达式,expression,
expr 1+2(不对
expr 1 + 2(返回3
expr 5\* 2(需要转义
或者上面讲过的,这样必须加上echo进行返回
echo $[5*2]
echo $((5*2))
条件判断
[atguigu@hadoop101 shells]$ [ 23 -ge 22 ]
[atguigu@hadoop101 shells]$ echo $?
0
[atguigu@hadoop101 shells]$ [ -w|e helloworld.sh ](权限,文件是否存在
[atguigu@hadoop101 shells]$ echo $?
0
[atguigu@hadoop101 ~]$ [ atguigu ] && echo OK || echo notOK
OK
[atguigu@hadoop101 shells]$ [ ] && echo OK || echo notOK
notOK
流程控制
- IF 基本语法
if [ 条件判断式 ]
then
程序
elif [ 条件判断式 ]
then
程序
else
程序
fi
实例
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "banzhang zhen shuai"
elif [ $1 -eq 2 ]
then
echo "cls zhen mei"
fi
[atguigu@hadoop101 shells]$ chmod 777 if.sh
[atguigu@hadoop101 shells]$ ./if.sh 1
banzhang zhen shuai
- CASE 基本语法
case $变量名 in
"值 1")
如果变量的值等于值 1,则执行程序 1
;;
"值 2")
如果变量的值等于值 2,则执行程序 2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
实例
[atguigu@hadoop101 shells]$ touch case.sh
[atguigu@hadoop101 shells]$ vim case.sh
!/bin/bash
case $1 in
"1")
echo "banzhang"
;;
"2")
echo "cls"
;;
*)
;;
esac
[atguigu@hadoop101 shells]$ chmod 777 case.sh
[atguigu@hadoop101 shells]$ ./case.sh 1
1
- for 基本语法1(我们熟悉但不是shell中常用的
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
实例
[atguigu@hadoop101 shells]$ touch for1.sh
[atguigu@hadoop101 shells]$ vim for1.sh
#!/bin/bash
sum=0
for((i=0;i<=100;i++))
do
sum=$[$sum+$i]
done
echo $sum
[atguigu@hadoop101 shells]$ chmod 777 for1.sh
[atguigu@hadoop101 shells]$ ./for1.sh
5050
基本语法2
for 变量 in 值 1 值 2 值 3…
do
程序
done
实例
[atguigu@hadoop101 shells]$ touch for2.sh
[atguigu@hadoop101 shells]$ vim for2.sh
#!/bin/bash
#打印数字
for i in cls mly wls
do
echo "ban zhang love $i"
done
[atguigu@hadoop101 shells]$ chmod 777 for2.sh
[atguigu@hadoop101 shells]$ ./for2.sh
ban zhang love cls
ban zhang love mly
ban zhang love wls
再来感受一下$@和$*
- while
比较推荐let写法
- 读取控制台输入
函数
$符
"$1"_log_$(date +%s)
chmod +x cmd_test.sh
./cmd_test.sh atguigu
- basename 输出相对路径
- dirname 输出绝对路径
- 自定义函数
调用前必须声明(因为不是编译型语言)
$?获取返回值
返回会限制在0~255中,可以不要return,直接echo $s
这样就正常显示了
综合运用
保存结果,需要归档命令。如
需求:实现一个每天对指定目录归档备份的脚本,输入一个目录名称(末尾不带/),将目录下所有文件按天归档保存,并将归档日期附加在归档文件名上,放在/root/archive 下。 这里用到了归档命令:tar
#!/bin/bash
#判断参数是否为1
if [ $# -ne 1]
then
echo"参数数量应为1"
exit
fi
# 从参数中获取目录名称
if [ -d $1 ]
then
echo
else
echo
echo "目录不存在"
echo
exit
fi
DIR_NAME=$(basename $1)
DIR_PATH=$(cd $(dirname $1); pwd)
# 获取当前日期
DATE=$(date +%y%m%d)
# 定义生成的归档文件名称
FILE=archive_${DIR_NAME}_$DATE.tar.gz
DEST=/root/archive/$FILE
# 开始归档文件
echo "开始归档..."
echo
# 用绝对路径很保险
tar -czf $DEST $DIR_PATH/$DIR_NAME
if[ $? -eq 0 ]
then
echo
echo "归档成功"
echo "归档文件为:$DEST"
echo
else
echo "归档有问题"
echo
fi
exit
chmod u+x daily_archive.sh
ll
#先创建目录
mkdir /root/archive
./daily_achive.sh ../scripts
#先创建目录
mkdir /root/archive
./daily_achive.sh ../scripts
编写定时脚本
分 时 日 月 年(*就不设定) 凌晨两点执行一个脚本自动归档
正则入门
文本处理工具
grep,sed,awk
^匹配开头
$匹配结束
* 不单独使用,匹配上一个字符匹配0次或多次
用正则匹配一个手机号,1[3578][0-9]
echo "138123456789" | grep ^1[345678][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$($表示结束
echo "138123456789" | grep -E ^1[345678][0-9]{9}$({}扩展)
文本处理工具
- cut 剪切
cut -d " " -f 1 cut.txt
cut -d " " -f 1 cut.txt(截取二三列,没有第三列就只显示第二列
cat /etc/passwd | grep bash$
- awk 文本分析工具,空格为默认分隔符,切片再进行分析处理
提取出一行文本,然后执行后面花括号的一系列命令
awk -选项参数 'pattern/{action}' ...
-F 指定输入文件分隔符
-v赋值一个用户定义变量
ll /usr/bin | grep awk
sudo cp /etc/passwd
#正则表达式 分隔符: 提取第7列
# 运用 grep 和 cut
cat /etc/passwd | grep ^root | cut -d ":" -f 7
#匹配后的传入{}代码块
# 一个awk直接实现grep 和 cut 的操作
cat /etc/passwd | awk -F ":" '/^root/{print $7}'
# 以,逗号分隔
cat /etc/passwd | awk -F ":" '?^root/{print $1","$6","$7}'
# 只显示第一列和第七列
cat /etc/passwd | awk -F ":" '{print $1","$7}'
# 自增1
cat /etc/passwd | awk -v i=1 -F : '{print $3+i}'
# 使用awk切割ip
实践
mesg(查看是否开启消息功能
who -T(同上
mesg y(开启
# 必须指定控制台
write atguigu pts/1
ctrl+C退出
# 脚本实现的方式
#!/bin/bash
# 查看user是否在线 -i忽略大小写$1第一个参数即用户 传参
login_user=$(who | grep -i -m 1 $1 | awk '{print $1}')
# -z zero 判断是否为0
if [ -z $login_user ]
then
echo "$1 不在线!"
echo "脚本退出.."
exit
fi
# 查看用户是否开启消息功能 截取第二列
is_allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}')
if [ $is_allowed != "+" ]
then
echo "$1 没有开启消息功能"
echo "脚本退出.."
exit
fi
# 确认是否有消息发送
if [ -z $2 ]
then
echo "没有消息发出"
echo "脚本退出.."
exit
fi
# 获取要发送的消息
whole_msg=$(echo $* | cut -d " " -f 2- )
# 获取终端
user_terminal=$(who | grep -i -m 1 $1 | awk '{print $2}')
# 写入要发送的信息
echo $whole_msg | write $login_user $user_terminal
if [ $? != 0 ]
then
echo "发送失败!"
else
echo "发送成功!"
fi
exit
完结撒花~~~~~~~~~