1 Shell概述
2 Shell解析器
1️⃣Linux提供的Shell解析器
cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
2️⃣bash和sh的关系
ll | grep bash
-rwxr-xr-x. 1 root root 941880 5月 11 2016 bash
lrwxrwxrwx. 1 root root 4 5月 27 2017 sh -> bash
3️⃣Centos默认的解析器是bash
echo $SHELL
/bin/bash
3 Shell脚本入门
1️⃣脚本格式
脚本以
#!/bin/bash
开头 : 指定解释器.
2️⃣第一个Shell脚本 : helloworld
① 需求 : 创建一个Shell脚本,输出helloworld.
② 案例实操
touch helloworld.sh
vim helloworld.sh
# 在helloworld.sh中输入如下内容
#!/bin/bash
echo "helloworld"
③ 脚本的常用执行方式
1) 采用bash
或sh+
脚本的相对路径或绝对路径(不用赋予脚本+x
权限)
sh+
脚本的相对路径 :
sh helloworld.sh
sh+
脚本的绝对路径 :
sh /home/xxx/datas/helloworld.sh
bash+
脚本的相对路径 :
bash helloworld.sh
bash+
脚本的绝对路径 :
bash /home/xxx/datas/helloworld.sh
2) 采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x
)
a) 首先要赋予helloworld.sh
脚本的+x
权限 :
chmod 777 helloworld.sh
b) 执行脚本 :
# 相对路径执行
./helloworld.sh
# 绝对路径执行
/home/xxx/datas/helloworld.sh
注意 : 第一种执行方法,本质是bash解析器在执行脚本,所以不需要执行权限;第二种执行方法则是自己执行,所以需要执行权限;
3️⃣第二个Shell
脚本 : 多命令处理
① 需求 : 创建一个文件并在文件中增加"I love you"语句.
② 案例实操 :
#!/bin/bash
cd /home/test
touch cls.txt
echo "I love cls" >>cls.txt
4 Shell中的变量
1️⃣ 系统变量
1) 常用系统变量
$HOME
$PWD
$SHELL
$USER
***
2) 案例实操
# 查看系统变量的值
echo $HOME
# 显示当前`Shell`中所有变量
set
2️⃣自定义变量
1) 基本语法
① 定义变量 : 变量 = 值
② 撤销变量 : unset
变量
③ 声明静态变量 : readonly
变量(注意:不能unset
)
2) 变量定义规则
① 变量名称可以由字母 数字和下划线组成,但是不能以数字开头,环境变量名建议大写
.
② 在bash
中,变量默认类型都是字符串类型,无法直接进行数值运算.
③ 在bash
中,变量默认类型都是字符串类型,无法直接进行数值运算.
④ 变量的值如果有空格,需要使用双引号或单引号括起来.
3) 案例实操
① 定义变量A
A=5
echo $A
② 给变量A重新赋值
A=8
echo $A
③ 撤销变量A
unset A
echo $A
④ 声明静态的变量B=2,不能unset
readonly B=2
⑤ 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
C=1+2 // 1+2
⑥ 变量的值如果有空格,需要使用双引号或单引号括起来
D="I love you"
⑦ 可把变量提升为全局环境变量,可供其他shell程序使用
export B
3️⃣ 特殊变量
$n
:n
为数字,$0
代表该脚本名称,$1-$9
代表第一到第九个参数,十以上的参数需要是使用大括号包含,如${10}
)
#!/bin/bash
echo "$0 $1 $2"
./parameter.sh cls xz
./parameter.sh cls xz
$#
: 获取所有输入参数个数,常用与循环
#!/bin/bash
echo $#
./parameter.sh cls xz
2
$*
: 代表命令行中所有的参数并把所有的参数看成一个整体
#!/bin/bash
echo $*
bash parameter.sh 1 2 3
1 2 3
$@
: 同样代表命令行中所有的参数,不同的是将每个参数区分对待
#!/bin/bash
echo $@
bash parameter.sh 1 2 3
1 2 3
$?
: 最后一次执行的命令的返回状态.如果值为0
证明正确执行,如果是非0
证明命令没有正确执行
echo $?
5 运算符
1️⃣ 基本语法
① "$((运算式))"
或"$[运算式]"
② expr + ,=,\*,/,%
(从左至右依次为 : 加,减,乘,除,取余)
③ 常用"\$[运算式]"
的形式
S=$[(2+3)*4]
echo $S
20
6 条件判断
1️⃣ 基本语法
[ condition ]
: 条件前后需要有空格,条件非空则为true
,反之为false
.
2️⃣ 常用判断条件
① 两个整数之间比较
=
: 字符串比较
-lt
: 小于
le
: 小于且等于
eq
: 等于
-gt
: 大于
-ge
: 大于且等于
-ne
: 不等于
② 按照文件权限进行判断
-r
: 有读的权限
-w
: 有写的权限
-x
: 有执行的权限
③ 按照文件类型进行判断
-f
: 文件存在并且是一个常规的文件
-e
: 文件存在
-d
: 文件存在且是一个目录
3️⃣案例实操
① 23
是否大于等于22
[ 23 -ge 22 ]
② helloworld.sh
是否具有写权限
[ -w helloworld.sh ]
③ /home/xxx/cls.txt
目录中的文件是否存在
[ -e /home/atguigu/cls.txt ]
④ 多条件判断(&&
表示前一条命令执行成功时,才执行后一条命令,||
表示上一条命令执行失败后,才执行下一条命令)
[ condition ] && echo OK || echo notok
7 流程控制
1️⃣if
判断
① 基本语法
# 注意事项:
#(1)[ 条件判断式 ],中括号和条件判断式之间必须有空格
#(2)if后要有空格
if [ 条件判断式 ];then
程序
fi
或者
if [ 条件判断式 ]
then
程序
elif [ 条件判断式 ]
then
程序
else
程序
fi
② 案例实操
# 输入一个数字,如果是1,则输出helloworld1;
# 如果是2则输出helloworld2;
# 如果是其他则输出helloworld3.
#!/bin/bash
if [ $1 -eq "1" ]
then
echo "helloworld1"
elif [ $1 -eq "2" ]
then
echo "helloworld1"
else
echo "helloworld3"
fi
2️⃣case
语句
① 基本语法
# 注意事项:
# 1 case行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
# 2 双分号“;;”表示命令序列结束,相当于java中的break。
# 3 最后的“*)”表示默认模式,相当于java中的default。
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
② 案例实操
# 输入一个数字,如果是1则输出1;
# 如果是2,则输出2;如果是其它,输出3。
#!/bin/bash
case $1 in
"1")
echo "1"
;;
"2")
echo "2"
;;
*)
echo "3"
;;
esac
3️⃣ for
循环
① 基本语法
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
for 变量 in 值1 值2 值3…
do
程序
done
② 案例实操
# 从1加到100
#!/bin/bash
s=0
for((i=0;i<=100;i++))
do
s=$[$s+$i]
done
echo $s
# 打印所有输入参数
#!/bin/bash
for i in $*
do
echo "helloworld + $i "
done
注意 :
1. $*和$@都表示传递给函数或脚本的所有参数,不被双引号“”包含时,都以$1 $2 …$n的形式输出所有参数。
2. 当它们被双引号“”包含时,“$*”会将所有的参数作为一个整体,以“$1 $2 …$n”的形式输出所有参数;“$@”会将各个参数分开,以“$1” “$2”…”$n”的形式输出所有参数。
#!/bin/bash
for i in "$*"
#$*中的所有参数看成是一个整体,所以这个for循环只会循环一次
do
echo "$i"
done
for j in "$@"
#$@中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次
do
echo "$j"
done
bash for.sh cls xz bd
cls xz bd
cls
xz
bd
4️⃣ while循环
① 基本语法
while [ 条件判断式 ]
do
程序
done
② 案例实操
# 从1加到100
#!/bin/bash
s=0
i=1
while [ $i -le 100 ]
do
s=$[$s+$i]
i=$[$i+1]
done
echo $s
8 read读取控制台输入
1️⃣ 基本语法
read
(选项)(参数)
选项:
-p
:指定读取值时的提示符;
-t
:指定读取值时等待的时间(秒)。
参数
变量:指定读取值的变量名
2️⃣ 案例实操
# 提示7秒内,读取控制台输入的名称
#!/bin/bash
read -t 7 -p "Enter your name in 7 seconds " NAME
echo $NAME
9 系统函数
1️⃣ 系统函数
①
basename
基本语法
basename [string / pathname] [suffix]
:basename
命令会删掉所有的前缀包括最后一个(‘/’)
字符,然后将字符串显示出来。
选项:
suffix
为后缀,如果suffix
被指定了,basename
会将pathname
或string
中的suffix
去掉。
② 案例实操
# 截取该/home/xxx/banzhang.txt路径的文件名称
basename /home/xxx/test.txt
test.txt
③
dirname
基本语法
dirname
文件绝对路径 : 从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分)
④ 案例实操
# 获取test.txt文件的路径
dirname /home/xxx/test.txt
/home/xxx
⑤ 自定义函数
1.基本语法
[ function ] funname[()]
{
Action;
[return int;]
}
funname
2.经验技巧
(1)必须在调用函数地方之前,先声明函数,shell脚本是逐行运行。不会像其它语言一样先编译。
(2)函数返回值,只能通过$?系统变量获得,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)
⑥ 案例实操
# 计算两个输入参数的和
#!/bin/bash
function sum()
{
s=0
s=$[ $1 + $2 ]
echo "$s"
}
read -p "Please input the number1: " n1;
read -p "Please input the number2: " n2;
sum $n1 $n2;
10 Shell工具
1️⃣ cut
cut
的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。cut
命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。
- 基本用法
cut [选项参数] filename
说明:默认分隔符是制表符
2.选项参数说明
- 案例实操
# 1. 数据准备
touch cut.txt
vim cut.txt
dong shen
guan zhen
wo wo
lai lai
le le
# 2 切割cut.txt第一列
cut -d " " -f 1 cut.txt
dong
guan
wo
lai
le
# 3 切割cut.txt第二、三列
cut -d " " -f 2,3 cut.txt
shen
zhen
wo
lai
le
# 4. 在cut.txt文件中切割出guan
cat cut.txt | grep "guan" | cut -d " " -f 1
guan
# 5. 选取系统PATH变量值,第2个“:”开始后的所有路径:
echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/xxx/bin
echo $PATH | cut -d: -f 2-
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/xxx/bin
# 6. 切割ifconfig 后打印的IP地址
ifconfig eth0 | grep "inet addr" | cut -d: -f 2 | cut -d" " -f1
192.168.1.102
2️⃣ sed
sed
是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed
命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。
- 基本用法
sed [选项参数] ‘command’ filename
- 选项参数说明
- 命令功能描述
- 案例实操
# 1. 数据准备
touch sed.txt
vim sed.txt
dong shen
guan zhen
wo wo
lai lai
le le
# 2. 将“mei nv”这个单词插入到sed.txt第二行下,打印
sed '2a mei nv' sed.txt
dong shen
guan zhen
mei nv
wo wo
lai lai
le le
cat sed.txt
dong shen
guan zhen
wo wo
lai lai
le le
`注意:文件并没有改变`
# 3 删除sed.txt文件所有包含wo的行
sed '/wo/d' sed.txt
dong shen
guan zhen
lai lai
le le
# 4 将sed.txt文件中wo替换为ni
sed 's/wo/ni/g' sed.txt
dong shen
guan zhen
ni ni
lai lai
le le
`注意:‘g’表示global,全部替换`
# 5 将sed.txt文件中的第二行删除并将wo替换为ni
sed -e '2d' -e 's/wo/ni/g' sed.txt
dong shen
ni ni
lai lai
le le
3️⃣ awk
一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
- 基本用法
awk [选项参数] ‘pattern1{action1} pattern2{action2}...’ filename
pattern:表示AWK在数据中查找的内容,就是匹配模式
action:在找到匹配内容时所执行的一系列命令
- 选项参数说明
- 案例实操
# 1. 数据准备
sudo cp /etc/passwd ./
# 2. 搜索passwd文件以root关键字开头的所有行,并输出该行的第7列
awk -F: '/^root/{print $7}' passwd
/bin/bash
# 3. 搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”号分割
awk -F: '/^root/{print $1","$7}' passwd
root,/bin/bash
`注意:只有匹配了pattern的行才会执行action`
# 4. 只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面添加列名user,shell在最后一行添加"dahaige,/bin/zuishuai"
awk -F : 'BEGIN{print "user, shell"} {print $1","$7} END{print "dahaige,/bin/zuishuai"}' passwd
user, shell
root,/bin/bash
bin,/sbin/nologin
。。。
xxx,/bin/bash
dahaige,/bin/zuishuai
`注意:BEGIN 在所有数据读取行之前执行;END 在所有数据执行之后执行。`
# 5. 将passwd文件中的用户id增加数值1并输出
awk -v i=1 -F: '{print $3+i}' passwd
1
2
3
4
- awk的内置变量
- 案例实操
# 1. 统计passwd文件名,每行的行号,每行的列数
awk -F: '{print "filename:" FILENAME ", linenumber:" NR ",columns:" NF}' passwd
filename:passwd, linenumber:1,columns:7
filename:passwd, linenumber:2,columns:7
filename:passwd, linenumber:3,columns:7
# 2. 切割IP
ifconfig eth0 | grep "inet addr" | awk -F: '{print $2}' | awk -F " " '{print $1}'
192.168.1.102
# 3. 查询sed.txt中空行所在的行号
awk '/^$/{print NR}' sed.txt
5
4️⃣ sort
sort
命令是在Linux
里非常有用,它将文件进行排序,并将排序结果标准输出。
- 基本语法 :
sort(选项)(参数)
参数:指定待排序的文件列表
- 案例实操
# 1. 数据准备
touch sort.sh
vim sort.sh
bb:40:5.4
bd:20:4.2
xz:50:2.3
cls:10:3.5
ss:30:1.6
# 2. 按照“:”分割后的第三列倒序排序。
sort -t : -nrk 3 sort.sh
bb:40:5.4
bd:20:4.2
cls:10:3.5
xz:50:2.3
ss:30:1.6
11 常见问题汇总
# 问题1:使用Linux命令查询file1中空行所在的行号
awk '/^$/{print NR}' file1.txt
# 问题2:有文件chengji.txt内容如下:
# 张三 40
# 李四 50
# 王五 60
# 使用Linux命令计算第二列的和并输出
cat chengji.txt | awk -F " " '{sum+=$2} END{print sum}'
150
# 问题3:Shell脚本里如何检查一个文件是否存在?如果不存在该如何处理?
#!/bin/bash
if [ -f file.txt ]; then
echo "文件存在!"
else
echo "文件不存在!"
fi
# 问题4:用shell写一个脚本,对文本中无序的一列数字排序
cat test.txt
9
8
7
6
5
4
3
2
10
1
sort -n test.txt|awk '{a+=$0;print $0}END{print "SUM="a}'
1
2
3
4
5
6
7
8
9
10
SUM=55
# 问题5:请用shell脚本写出查找当前文件夹(/home)下所有的文本文件内容中包含有字符”shen”的文件名称
grep -r "shen" /home | cut -d ":" -f 1
/home/xxx/datas/sed.txt
/home/xxx/datas/cut.txt
12 常用脚本
- 环境初始化脚本
#!/bin/bash
#读取用户输入
read -t 10 -p "Enter your user name in 7 seconds " username
read -t 10 -p "Enter your folder name in 7 seconds " foldernameone
read -t 10 -p "Enter your folder name in 7 seconds " foldernametwo
read -t 10 -p "Enter your starting value in 7 seconds " minvalue
read -t 10 -p "Enter your end value in 7 seconds " maxvalue
read -t 10 -p "Enter your ip number in 7 seconds " ip
#关闭防火墙
echo "关闭防火墙"
service iptables stop
chkconfig iptables off
#创建一个一般用户
echo "创建一般用户"
useradd $username
echo "123456" | passwd $username --stdin
#创建目录
echo "创建目录"
mkdir /opt/$foldernameone /opt/$foldernametwo
chown $username:$username /opt/$foldernameone /opt/$foldernametwo
#加入Sudoers
echo "加入Sudoers"
sed -i "/^root/a $username ALL=(ALL) NOPASSWD: ALL" /etc/sudoers
lan=`ifconfig | grep Bcast | cut -d . -f 3`
#改Host
echo "修改hosts"
for ((i=$minvalue;i<$maxvalue;i++))
do
echo "192.168.$lan.$i hadoop$i" >> /etc/hosts
done
#改网卡
echo "修改网卡"
cat </etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.$lan.$ip
PREFIX=24
GATEWAY=192.168.$lan.2
DNS1=192.168.$lan.2
NAME=eth0
EOF
#改主机名
echo "修改主机"
sed -i "s/HOSTNAME=.*/HOSTNAME=hadoop$ip/g" /etc/sysconfig/network
#改网卡脚本
echo "修改网卡"
sed -i '/eth0/d' /etc/udev/rules.d/70-persistent-net.rules
sed -i 's/eth1/eth0/g' /etc/udev/rules.d/70-persistent-net.rules
#重启使配置生效
reboot