Hadoop(一)

一、大数据和云计算的关系?
  周围总是充斥着大数据和云计算这两个词,然而,实际上,很多人对于云计算和大数据的关系却总是容易混淆,所以总是将“云计算”和“大数据”放在一起讨论, 实则不然。
大数据和云计算究竟有什么关系?
什么是云?
是个概念,虚无缥缈的,天上飘着的,电视云,手机云,百度云,能用,能看得见吗?
但是云落地了,是不是就存在了?
  简单来说:云计算是硬件资源的虚拟化,而大数据是海量数据的高效处理。
虽然从这个解释来看也不是完全贴切,但是却可以帮助对这两个名字不太明白的人很快理解其区别。当然,如果解释更形象一点的话,


云计算相当于我们的计算机和操作系统,将大量的硬件资源虚拟化后再进行分配使用。在云计算领域目前的老大应该算是Amazon,可以说为云计算提供了商业化的标准,另外值得关注的还有VMware(其实从这一点可以帮助你理解云计算和虚拟化的关系),IBM,开源的云平台最有活力的就是Openstack了;


  可以说,大数据相当于海量数据的“数据库”,通观大数据领域的发展我们也可以看出,当前的大数据发展一直在向着近似于传统数据库体验的方向发展,一句话就是,传统数据库给大数据的发展提供了足够大的空间。


  大数据的总体架构包括三层:数据存储,数据处理和数据分析。(汉堡)数据先要通过存储层存储下来,然后根据数据需求和目标来建立相应的数据模型和数据分析指标体系对数据进行分析产生价值。


  而中间的时效性又通过中间数据处理层提供的强大的并行计算和分布式计算能力来完成。三者相互配合,这让大数据产生最终价值。


  不看现在云计算发展情况,未来的趋势是:云计算作为计算资源的底层,支撑着上层的大数据处理,而大数据的发展趋势是,实时交互式的查询效率和分析能力,借用Google一篇技术论文中的话:“动一下鼠标就可以在秒级操作PB级别的数据”,确实让人兴奋不能止。




二、安装VMware虚拟机
快捷键
基本操作和命令
Ctrl+G 进入VMware界面
Ctrl+Alt 退出此界面


1、虚拟机BIOS设置问题:
(1)F2进入
(2)设置为Enabled
具体搜索:电脑型号+虚拟机BIOS设置


戴尔  F2
联想  左边有个按钮或针孔,重启时按下
惠普    F10


2、虚拟机分区操作:
分区 数据类型   分配空间
/boot ext4 300 Fixed size(启动分区,存放内核信息和启动程序)
swap 2048 Fixed size(交换分区,一般情况:虚拟内存的两倍)
/ ext3 300 Fill.....(/相当于windows的C盘)


3、网络常识
每次装新系统,装完VMware时候需要把ip地址改成自己习惯的一个网段,即本机和虚拟机在同一网段,这样才能联通两个机子,否则不在同一网段无法连通
虚拟机和本机(笔记本)通过VMware NET1连接


网络常识:点分十进制
0-255
0是被禁用的,代表该网段的网段号,无意义
255也是被禁用的,代表该网段的广播地址,交换机默认使用它用来进行广播
1和254是路由(1代表真实路由;254代表虚拟路由)


ip:192.168.10.254
子网掩码:225:225:225:0(等于24)






一、Linux
1、什么是Linux ?
1991年(第一次正式对外公布)
Linux是一套免费使用和自由传播的类Unix的操作系统
C语言编写
以网络为核心


应用:
Linux可以安装在各种计算机和别的硬件设备中:
eg:手机,平板,台式机,大型机,超级计算机、视屏游戏控制台




2、Linux的主要特性?
基本思想:
(1)一切皆文件
(2)每个软件都有固定的用途


(1)免费开源
(2)多用户、多任务
(3)良好的界面(字符界面和图面界面)
字符界面--可以输入命令进行操作
图面界面--类似于windows的界面,可以说是一个Linux版的windows


(4)支持运行在多种平台
(eg:手机,平板,台式机,大型机,超级计算机、视屏游戏控制台)






3、常用Linux版本?
Red Hat:
商业版(收费),企业级的LInux (80-110元)


Fedora Core:
由原来的Red Hat桌面版发展而来,免费版本(家用)


Centos:Red Hat社区克隆版本,免费
Debian:经常应用于服务器,性能稳定
Ubuntu:Debian衍生而来的,比较流行的桌面系统


Fedora:急于尝试新技术,等不及稳定版本,一个测试平台




4、Linux的根目录介绍?
/bin和/usr/bin :二进制文件,包括root用户和普通用户的操作命令,shell解析器
/sbin:系统管理员root才能使用的命令


/boot:系统引导和内核目录,存放引导装载文件(启动分区,启动程序和内核)
/dev:设备目录,eg:cpu,input,disk
/home:所有用户的家目录
/lib:系统使用的函数库的目录
media:媒体目录,多媒体文件夹
/lost+found:系统崩溃时的信息存储位置
/opt:给主机额外安装软件存放目录
/tmp:存放程序产生的临时文件(关机重启信息清空)
/var:系统一般运行时需要改变的数据存储位置
/sys:系统的相关文件存放目录
/usr:存放应用程序相关的目录命令、函数库、共享包、内核源码
/proc:重要的需要存放在内存中的数据


二、常见Linux命令


Table:
(1)自动补全命令或目录
(2)在某个目录下只有一个目录时无需输入首字母敲Tab自动补全目录
(3)双击Tab:显示所有命令
列出某个目录下的所有文件


常识及命令:
关机:init 0 或 shutdown -h now//把now改成数字是对应的分钟数
shutdown -t 10000 -h now "System will be shutdown 10 seconds later"
双引号里不能加标点符号


wall "System will be shutdown 10 seconds later" && sleep 10 && shutdown -h now
前部分可省略  sleep 10 && shutdown -h now
先睡眠10秒然后关闭


重启:init 6 或reboot


Ctrl+C:强制退出
Ctrl+Alt:退出虚拟机界面
Ctrl+G:进入虚拟机界面
clear:清空屏幕信息


cd ./ 当前目录
cd ../ 返回上一级目录
cd - 返回上一次操作的目录
cd ~ 回到root用户的家目录


clear 清屏


ls(list)查看命令(相当于windows的dir)
ls 列出当前目录下的所有目录
ls /home/bigdata
ls -l(等于ll,等于-l) 列出当前目录下的所有目录的详细信息




pwd //显示当前目录




修改VMware的操作界面模式:


vi /etc/inittab //修改id后面的数字3或5,保存退出,重启生效,无需使用source /etc/inittab
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id:5:initdefault:


公司用id3:全命令模式,无图,无鼠标指针,公司正常模式,可节省内存100-200M
几乎不用id5:windows-x11图形界面


4.挂载光驱:
mount -t iso9660 /dev/cdrom  /mnt/cdrom
   取消挂载
umount /mnt/cdrom


5.如何显示彩色目录列表?
打开 vi /etc/bashrc ,加入下一行:按i进入命令编辑模式(可以在此界面增加。删除东西)
alias ls="ls --color"    声明一个要起的别名
改完之后按一下ESC键(最后一行insert消失),然后输入:wq


最后执行:source /etc/bashrc       //使刚才的操作生效
或则重启虚拟机,或关机重启


下次启动bash时候就可以像Slackware里那样显示彩色的目录列表了,其中颜色的含义如下:
1.蓝色-->目录
2.绿色-->可执行
3.红色-->压缩文件
4.浅蓝色-->链接文件
5.黑色-->其他文件


6.查看Linux系统信息(-a,-s,-n,-r,-v-m,-p,-i,-o--help,--version)
uname -a  //打印Linux系统所有信息(内核名称--系统名称,主机名,内核版本号,内核版本,硬件名,处理类型,硬件平台类型,操作系统名称)
uname -n //主机名
uname -s //内核名称
uname -r //内核版本号
uname -v //内核版本
uname -m //硬件平台类型


7.查看系统小版本
cat /etc/redhat-release


8.查看进程
ps -fe(查看所有Linux进程)
ps -fe | grep java  (管道把所有进程过滤一遍显示java进程)


9.查看守护进程树
pstree


10.打印当前正在运行的进程,以及它对内存,CPU,硬盘的占用率
top -s //任务数,已经在运行进程对cpu的占用率,硬盘,交换分区
终止 按:Ctrl+C


11.显示磁盘空间
df -h //显示磁盘分区详细信息(磁盘名,总大小,已用空间,空间使用率)


查看磁盘分区:
faisk-1
挂载分区:
mount /dev/sda3  /home/data
查看分区是否挂载成功:
df -TH /home/data
取消挂载:
umont  /home/data




(一)用户操作
1.创建用户
# useradd 用户名
查看用户名:cat /etc/passwd
# passwd 用户名
输入两遍密码
报 updated successfully ; 密码设置成功了
查看用户密码:cat /etc/shadow            //密码以md5加密
# id 用户名//查看用户信息
0-499管理员  >=500普通用户   0--root


# groups 用户名 //查看用户所属组


2.修改密码
方式一 :
# passwd  用户名 回车,然后输入新密码


方式二:
# echo "wef"
把双引号里的字符打印到显示屏上
密码
# echo "1234" | passwd --stdin 用户名  //修改用户密码(仅限于当前用户是root才能修改密码) 
|  代表管道 , 相当于grep


#groups 用户名 // 查看用户所属组
# id 用户名  //查看用户信息
1-500管理员      >=500普通用户


方式三: Linux 不进去系统更改root密码(Linux暴力的破解密码)
先将输入定项到该虚拟机,即在虚拟机内部单机或是按Ctrl+G
1.进入grub界面后,在3秒内按回车,进入
2.选项菜单按e进入编辑模式
3.编辑kernel那行  输入"1"(空格1)或者“single”
4.按B重启保存的
5.进入后执行下列命令
   root@#passwd root (配置root用户的密码)


   Enter new unix password; 输入新的密码
6.执行命令 root@# init 6 或 reboot


3.删除用户
# userdel 用户名  //删除用户信息,不删除用户文件


4.用户切换
su  普通用户用户名(root到普通用户无需密码)
su - 等于 su root (从普通用户切换到root需要密码)
输入root用户密码


5.查看用户
who am i  //显示用户名,用户组,时间(是登录的用户)
whoami  //只显示用户名(当前状态下的用户)
who  //用户连接方式,Try意味着用户直接链接到电脑上,而pts意味着远程登录(当前状态下的用户和登录的用户)


6.用户组
(1)添加用户组
groupadd  组名
(2)删除用户组
groupdel  组名
直接删除空组,如果组内有用户,则删除用户,再删除组
(3)添加用户到指定用户组(组名必须存在,路径重新创建,用户名为新用户)
useradd  -g 组名 -d 路径 用户名
添加用户到指定组(用户名不能存在)
useradd -g 501 用户名  
(4)修改用户到指定用户组3
usermod  -g 组名 -d 路径 用户名
修改用户组
usermod -g 组号 用户名
(5)查看用户组
# cat  /etc/group
groups


7.让普通用户执行root用户操作
添加写权限
chmod 755 /etc/sudoers  //777是最大权限  常用755
chmod u+r+w+x  /etc/sudoers
(u表示当前用户,g表示同组用户,o表示其他用户,a表示所有用户)


chmod  u+w  /etc/sudoers   //增加当前用户的写权限
chmod  u-r  /etc/sudoers   //取消当前用户的读权限
chmod  g-r  /etc/sudoers   // 取消当前用户及其同组的所有用户的读权限


让普通用户拥有root用户权限
vi  /etc/sudoers
按i修改文件  Enter换行
aa  ALL=(root)NOPASSWD:ALL


保存退出:按ESC :wq


q! //强制退出




生效方法:
(1)source /etc/sudoers  //使修改操作生效
(2)重启虚拟机 :reboot或init 6


8.用户文件授权
r4  w2  x1
1)文件类型
-  文件
d  文件夹


2)r可读w可写d可执行


r4  w2  x1
从0-7的意义
0  ---
1  --x
2  -w-
3  -wx
4  r--
5  r-x
6  rw-
7  rwx




(二)文件格式
Linux下的文件格式:ext4磁盘格式  vfat可移动的设备格式


Windows下的文件格式:fat32(单个文件大小最大32G) ntfs
Linux与Windows之间的数据拷贝必须是vfat格式


(三)文件操作
pwd  查看当前目录(绝对路径)
ls显示目录信息(蓝色:目录  黑色:文件)
cd 路径名  //进入那个文件夹下


1.创建文件和目录
建目录:
mkdir 目录名   # cd进入目录
建文件
vi  文件名
vim  文件名
touch  文件名


查看文件内容:
# cat 文件名  //一个页面显示所有内容
# more 文件名 //分页显示文件内容 ,按enter进入没显示完的内容


(1)编辑模式(3种)
一般模式:
进入编辑模式之前,其他模式之下,按ESC进入此模式
命令模式:
命令行界面
编辑模式:
进入一般模式,按i进入编辑模式,可以对文件进行操作


按i修改文件 Enter换行
保存退出:ESC  :wq
强制退出不保存 :q!
退出不保存 :q
(cp,mv 不支持跨文件修改文件名,只能是源文件文件名,当前目录下可修改)


2.复制文件并且重命名
cp 源文件名 改后的名


3.复制目录
cp -r 源文件名 改后的名


4.移动,剪切,重命名
mv 源文件名 改后的名


5.删除
# rm 文件名 //删除文件
# rm -r 文件名//Linux下删除文件会不断弹出询问窗口(是否删除)
# rm -f 文件名//强制删除
# rm -rf 文件名//强制删除文件且不可恢复


6.查看文件内容
# cat -n 文件名//有行号显示文件内容(n代表number)
# cat 文件名 //无行号显示文件内容


7.设置文件权限
chmod 755 /etc/sudoers  //777是最大权限  常用755
chmod  u+w  /etc/sudoers   //增加当前用户的写权限(u表示当前用户,g表示同组用户,o表示其他用户,a表示所有用户)
chmod  u-r  /etc/sudoers   //取消当前用户的读权限
chmod  g-r  /etc/sudoers   // 取消当前用户及其同组的所有用户的读权限


8.显示文件前。。行, 后。。行(不常用)
head 文件名 //默认查看前10行
tail 文件名 //默认查看后10行


(把n换成数字)
head -n 文件名 //默认查看前几行
tail -n 文件名 //默认查看后几行


#cat -n 文件名 //查看文件一共有多少行


9.追加文件内容
echo "agradabaf">jiao  追加覆盖原来内容
echo "adadnwind">>jiao  追加不覆盖原有内容


10.文本编辑


(1)编辑模式
一般模式:
进入编辑模式之前,其他模式之下,按ESC进入此模式
命令模式:
命令行界面
编辑模式:
进入一般模式,按i进入编辑模式,可以对文件进行操作
保存:w
保存退出:wq
强制退出:q!
退出不保存:q


(2)命令


vim 文件名 和 vi 文件名 都可以对文件进行编辑操作


vim 和 vi 区别?
vim是一个高级文本编辑器,只适用于图形化界面,可以对字体颜色加亮加深
vi是一个低级文本编辑器
vim和vi都是文本编辑工具,命令行模式一样,功能一样


11.打包,解包 原理


tar打包原理zxvf(解包tar.gz格式) xvf(解压普通tar包)  cvf
-c 打包(压包,添加压缩文件)
-z 压缩
-x 解包
-c 可以指定解包的位置
-v 输入显示(view)
-f 必须要(打包盒压包必须要-f)


(1)打包:(目的包-想要压缩之后的包在前,要打包的文件写后面)
打包一个文件:
目的包  源文件
tar -cvf a.tar  jiao.txt
tar -cf a.tar jiao.txt(加v显示源文件不现实文件,不加)


打包多个文件和目录
tar -cvf b.tar jiao.txt a  b 


打包所有照片
tar -cvf c.tar *.jpg


打包所有文件
tar -cvf d.tar *


打包多个文件和目录并压缩
tar -zcvf b.tar jiao.txt a b 


(2)解包:(不能加z)
不指定解包位置
tar -xvf a.tar
指定解包位置
tar -xvf a.tar -C /home/aa


压缩包的名字在前,目录在后
/home/aa此目录必须存在


查询命令:(相当于windows的搜索引擎)
12.which
which reboot //查看reboot命令所在文件位置
13.locate
# locate 文件名(或命令)
14.find
# find 文件名(或命令)


15.locate,which,find的区别?
locate 和which这个命令功能一样,但是locate的查询效率比which要快一点,文件不太多的话--正常快0.0几秒,其中find命令(必须进入要查找文件的上一级目录或是要查找命令的所在目录),运行效率低


16.帮助命令--list ,--help,man ,info
eg:
# /etc/init.d/NetworkManger --list
# man ls(q退出)


# ls --help
# info ls(查看时候用键盘方向键或是pageup,pagedown;退出:q或者Ctrl+C)


17.给shell命令起别名
vi /etc/bashrc


起别名 名字=功能(命令)
alias cls='clear'
ESC  :wq


重启生效(必须)
source /etc/bashrc
init 6 或reboot


系统配置文件在系统启动过程中加载;对系统配置文件进行修改时需要重启生效,是哟个source的一个加载命令:source系统配置文件路径 或是init 6 或reboot


(四)Linux网路与安全
1.每次装新系统,装完VMware时候需要把ip地址改成自己习惯的一个网段,即本机和虚拟机在同一网段,这样才能联通两个机子,否则不在统一网段无法连通
虚拟机和本机(笔记本)通过VMware NET1连接


2.网路常识:点分十进制
0-255
0是被禁用的,代表该网段的网段号,无意义
255也是被禁用的,代表该网段的广播地址,交换机默认使用它用来进行广播
1和254是路由(1代表真实路由;254代表虚拟路由)


ip:192.168.10.254
子网掩码:255.255.255.0(等于24)
默认网关


3.网络连接方式
1.桥接NAT---NAT8
虚拟机与宿主机在同一个局域网中,ip地址容易冲突
2.网络模式---NAT0
利用宿主机的网卡进行外网连接,可以上网
3.仅主机模式--NAT1
是把宿主机器当作一个路由器,虚拟机连接这个路由器,形成局域网
不能连接外网,大数据常用


1.主机名
# hostname  //查看当前主机
# hostname 主机名 //临时修改主机名
# vi /etc/sysconfig/network  //永久性修改主机名
HOSTNAME=主机名


# service network restart //重启网卡


2.常见服务端口
web tcp 80  //80系统端口,8080自定义端口tcp的默认端口
telnet tcp 23 //远程访问telnet
ssh tcp 22 //安全连路 ssh和telnet是网络通讯连接的两种方式
ftp tcp 20/21  //stp


3.映射文件
vi /etc/hosts
ip 主机名
ip 网站名


windows:
C:\Windows\System32\drivers\etc\hosts
添加一行:
192.168.10.21 j
ip主机名


4.关闭Linux防火墙(默认装完虚拟机开启防火墙)
# service iptables status //查看防火墙状态
# service iptables --list //查看防火墙用法
# service iptables start/stop  //关闭防火墙
# chkconfig iptables off/save //保存防火墙开机不启动


# service iptables save  //开机启动防火墙(不用执行它)


# /etc/init.d/NetworkManger stop //关闭网络管理服务信息
# chkconfig NetworkManger off //保存网络管理服务信息开机不启动


# iptables -F //清除防火墙


//关闭网络信息管理
# service network stop //关的是eth0接口 ,图表不存在
# /etc/init.d/NetworkManger stop //这个只是关闭网络管理信息,图标还存在
# /etc/init.d/NetworkManger status   //查看网络信息管理状态


init 和 init.d区别:
init下是连接文件
init.d下放的是可执行文件


5.修改虚拟机ip
命令修改:
vi /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
改:HWADDR=00:0C:29:0A:A8:5E
TYPE=Ethernet
UUID=25e87ffd-4b50-4606-9afd-40402465f8f1//16进制a-f,0-9
改:ONBOOT=yes //默认是开机不启动,改成开机启动
NM_CONTROLLED=yes 网卡是否使用
改:BOOTPROTO=none //不启用dhcp协议,改为none
//是否启动PROTO协议  dhcp表示通过路由器动态获取地址,没有路由就把它先关了,再写IP地址


(下面内容手动添加)
IPADDR=192.168.10.10
PREFIX=24
GATEWAY=192.168.10.254
DEFROUTE=yes //默认使用路由
NAME="System eth0"




ping ip 不通就重启虚拟机或是网卡
# service network restart//重启网卡
全部显示ok,不需要重启
否则重启虚拟机:reboot或init6
ping 主机名
ping ip


windows搜索:cmd 
ping 主机名(不通)
ping ip


windows修改:
主机名ping不通:C:\Windows\System32\drivers\etc hosts


ip 主机名


手动点电脑图标修改网络信息:
右击网络图标(右上角小电脑)--Edit Connections--勾上Connect automatically--修改IPV4协议--连接方式改为手动--添加一个地址信息--add:address:192.168.10.21;netmask:24;gateway:192.168.10.254--apply应用--close关闭




三. Hadoop
1.Hadoop的历史:
Hadoop之父Doug Cutting(Apache基金会的主席),先带领他的团队创建了Lucene,Nutch,Hadoop等开源项目,最开始的时候Hadoop是Lucene的子项目,Nutch的一部分


Apache Lucene
全球的第一个开源的全文搜索搜索引擎工具包
完整的查询引擎和索引引擎
部分文本分析引擎


开发人员可在此基础上建立起完整的全文检索引擎


Nutch:
开源的Lucene的网页搜索引擎
加入网页抓取,解析等功能


Google
商业搜索引擎


Google的两篇重要论文:
GFS(Google File System):第一篇论文,即谷歌分布式文件存储系统
MapReduce:是一个框架,架构,解决分布式计算的难题


Google公司当时在论文中声称他们公司依靠这两种技术使得Google搜索的性能获得极大提升




Doug Cutting意识到了这两个技术可以应用到他的Nutch搜索引擎,带领团队成功移植了这两个技术,将这个技术作为了一个开源的框架,命名为Hadoop,最终Hadoop成为Apache 旗下顶级项目


大数据-数据分析展现--热力图




2、hadoop官网:http://hadoop.apache.org//


3、Hadoop LOGO 和名字的由来:
LOGO:是Doug Cutting女儿的黄色小象的颜色和外形
          __     __       
         /  \~~~/  \    
   ,----(     ..    ) 
  /      \__     __/   
 /|         (\  |(
^ \   /___\  /\ |   
   |__|   |__|-" 




名字:是他女儿给小象起的名字:Hadoop


4、Hadoop大事件
2002年 Nutch项目开始运行(作为Hadoop的前身)
2003年 谷歌发表GFS论文,介绍了谷歌的文件存储系统
2004年 Doug Cutting模仿谷歌创建了NDFS(Nutch Data File System )
2005年 Nutch移植到新的框架,Hadoop早期版本大概运行在20个节点(一个节点代表一台虚拟机)上(稳定运行)
2006年1-3月 Doug Cutting被雅虎聘请(这一年不仅是雅虎快速发展的一年,也是Hadoop快速发展的一年,雅虎出钱让他带团队改进Hadoop,并且求他把Hadoop应用到雅虎搜索上 )


进公司第二个月启动Apache Hadoop项目


2008年 Hadoop技术赢得了世界第一;200秒处理1TB数据,900多个节点完成


2013年 Hadoop技术峰会召开,表示进入了Hadoop 2.0*时代
2015年 参加China Hadoop submmit
2016年 提出hadoop3.0的理念、概念
2017年 正式发布hadoop3.0


四.集群搭建
1.Hadoop集群三种模式:
单机版:
一个节点(一台机子)


伪分布式集群:
一个节点模拟多个节点


全分布式集群:
真实集群,由多个节点组成


2、Hadoop三个版本
(1)Apache Hadoop(所有其他版本都是基于它开发的)
(2)CDH(Cloudera's  Distribute Including Apache Hadoop )收费,商业
(3)HDP(Hortonworks Data Paltform)
在中国的互联网公司多用CDH,政府是使用国内大数据平台公司的Hadoop


3、Hadoop环境支持
(1)JDK
(2)Hadoop


(公用)
查看防火墙状态:
service iptables status //查看防火墙状态
# service iptables stop //关闭防火墙
# chkconfig iptables off //保存防火墙开机不启动
主机名
# vi /etc/sysconfig/network //永久性修改主机名


改虚拟机ip
命令修改:
vi /etc/sysconfig/network-scripts/ifcfg-eth0
        00:0C:29:5C:B3:44
             手工配置
   DEVICE=eth0
       改:HWADDR=00:0C:29:74:E7:3E
       改:HWAADR=MAC地址
   TYPE=Ethernet
       改:UUID=d06a4eee-dd5c-45e5-afbc-38a8a8440bd9(是随机生成的,至少随机修改一位,0-9,a-f因为是16进制写的)10进制0-9   2进
0和1  8进制0-7(最好每次            都改一下,为了与其他机子避免重复)
       改:ONBOOT=yes        //默认是开机不启动,改成开机启动
           NM_CONTROLLED=yes   //网卡是否使用
       改: BOOTPROTO=none     //是否启动PROTO协议  dhcp表示通过路由器动态获取地址,没有路由就把它先关了,再写IP地址
       (添加下面所有内容)
        IPADDR=192.168.10.10
PREFIX=24 或255.255.255.0      //子网掩码   24代表三个网段255
GATEWAY=192.168.10.254        //网关,是VMware NET1的IP,它将通过这个机子与其他任何机子互连
    DNS1=192.168.10.254 //域名(暂时不写)
DEFROUTE=yes //是否开启默认路由
    IPV4_FAILURE_FATAL=yes   //失败检测(不写,一般公司要写)
    IPV6INIT=no              //是否使用IPV6(不写,一般公司要写)想开或是关改这个的yes或者no 就可以,不用再去找了
NAME="System eth0"          //给网卡起名(为了其他软件对此网卡进行管理)
最后一步保存退出(千万不能忘)


改映射文件:


vi /etc/hosts
192.168.10.2 b
ip 主机名


# ping 改后的ip   

# service network restart   //改完ip之后重启网卡
    如果不成功就重启 init 6
    # ping 改后的ip 
    # ping 主机名
    
改主机名和映射文件(修改后需重启生效)
windows的hosts文件位置:C:\Windows\System32\drivers\etc\hosts
192.168.10.10 m
dos命令:
# ping 改后的ip 
# ping 主机名


(一  搭建单机集群)
用wsc(勾选SFTP协议)给该机子导两个包:hadoop-2.7.1.tar.gz  jdk-7u79-linix-x64.tar.gz到/opt/bigdata下


将文件解包并解压缩
  # tar -zxvf hadoop-2.7.1.tar.gz        (常用方法)
  # tar -zxvf jdk-7u79-linix-x64.tar.gz
          # rm –rf jdk-7u79-linix-x64.tar.gz  //常用命令 删除不可恢复
  # mv hadoop-2.7.1 hadoop   //把hadoop-2.7.1移动到hadoop
  # ls
  # mv jdk1.7.0-79/ jdk
  # ls
  # which java  //查看Java路径(复制此路径/usr/bin/java)
  # mv /usr/bin/java /usr/bin/java.1


用xshell连接虚拟机:协议:ssh




修改系统环境变量
# vi /etc/profile
把pathmunge (){那行往下移


然后插入:
export JAVA_HOME=/opt/bigdata/jdk/
export HADOOP_HOME=/opt/bigdata/hadoop/


export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:


修改/etc/bashrc
添加一行 source /etc/profile




# source /etc/profile       //使修改后的系统生效


# java //检测JDK是否安装成功
# hadoop //检测Hadoop是否安装成功
[root@b1 ~]# which hadoop //查看hadoop的启动位置
/opt/bigdata/hadoop/bin/hadoop
[root@b1 ~]# which java 查看java程序的位置
/usr/bin/java
[root@b1 ~]# mv /usr/bin/java /usr/bin/java.1 //重命名一下
[root@b1 ~]# which java
/opt/bigdata/jdk/bin/java


(二  伪分布式集群)
步骤:
执行(公用) --> (一 单机)
修改hadoop配置文件


格式化:namenode
# hadoop namenode -format
# hdfs namenode -formart
格式化成功后的标志 successfully
17/07/19 13:06:02 INFO common.Storage: Storage directory /home/hadoopdata/dfs/name has been successfully formatted.
17/07/19 13:06:02 INFO common.Storage: Storage directory /home/hadoopdata/tmp/dfs/nameedits has been successfully formatted.


启动伪分布式集群:
# start-all.sh  //启动所有


[root@b home]# jps
3870 NameNode
4161 SecondaryNameNode
3997 DataNode
4754 Jps


或单独启动jps进程:
hadoop-daemon.sh start namenode
hadoop-daemon.sh start secondarynameNode
hadoop-daemon.sh start datanode


关闭集群所有进程
stop-all.sh
单个关闭集群jps进程
kill -9 id (jps 进程号)


(三  全分布式集群)
1.(公用) --> (一 单机)
关闭防火墙
修改主机名(如果是克隆的 删除udev--eth0)
修改ip
VMware 和dos命令都能ping通


2. SSH免密 (不需要输入密码)
[root@q1 ~]# ssh-keygen -t rsa   //启用SSH免密协议


Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase):
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
6c:0f:42:8d:0a:a8:b5:5f:c3:61:8a:6a:51:55:f7:c0 root@q1
The key's randomart image is:
+--[ RSA 2048]----+
|     ....o       |
| .  .  o.Eo      |
|. o.  = .  .     |
|...+ * o         |
|..o o = S        |
| ... . + o       |
|..  .     .      |
|.                |
|                 |
+-----------------+


免密操作:
# ssh-copy-id q1 需要免密的机子  //先确定要对这台虚拟机免密,然后输入密码
Now try logging into the machine, with "ssh 'q2'"  //免密成功
# ssh-copy-id q2
# ssh-copy-id q3
检验免密是否成功:
# ssh q1
# ssh q2
# ssh q3
[root@q1 ~]# ssh q3
Last login: Fri Jul 21 14:36:49 2017 from 192.168.10.254
[root@q3 ~]# exit
logout
Connection to q3 closed.


3.VMware和dos命令都能ping通
给q1虚拟机上传hadoop,jdk安装包
解压安装包
修改环境变量
# vi /etc/profile
# vi /etc/bashrc
# source /etc/profile


4.修改hadoop环境:
# vi hadoop-env.sh
/opt/bigdata/jdk


5.修改hadoop配置文件
core-site.xml
hadoop-env.sh (修改JAVA_HOME路径)
hdfs-site.xml
mapred-site.xml
slaves(一行一个主机名)
yarn-site.xml


6.分别把hadoop,jdk安装包传输给其他两个机子q2,q3
# scp -r /opt/bigdata/hadoop/ root@q2:/opt/bigdata/
# scp -r /opt/bigdata/jdk/ root@q2:/opt/bigdata/
# scp -r /opt/bigdata/hadoop/ root@q3:/opt/bigdata/
# scp -r /opt/bigdata/jdk/ root@q3:/opt/bigdata/


7.传输后,查看q2,q3的/etc/profile和/etc/bashrc是否修改
# source /etc/profile


8.在集群主节点格式化namenode进程
hdfs namenode -format
hadoop namenode -format


成功标志:
17/07/24 01:03:35 INFO common.Storage: Storage directory /home/hadoopdata/dfs/name has been successfully formatted.
启动集群


9)集群JPS(进程)启动方式:
1>start-all.sh
# mr-jobhistory-daemon.sh start historyserver
# yarn-daemon.sh start proxyserver 


2>start-dfs.sh
start-yarn.sh


# mr-jobhistory-daemon.sh start historyserver
# yarn-daemon.sh start proxyserver  




3>单进程启动
先启动dfs进程:
启动namenode、datanode、ResourceManager、NodeManager(组件先启动namenode,然后启动datanode,SecondaryNameNode)
hadoop-daemon.sh start namenode
sbin/hadoop-daemon.sh start datanode //启动datanode的jps进程
hadoop-daemon.sh start secondarynamenode
再启动yarn进程:
yarn-daemon.sh start nodemanager
yarn-daemon.sh start resourcemanager




10)如何启动历史服务?
# mr-jobhistory-daemon.sh start historyserver


11)启动proxyserver服务
yarn-daemon.sh start proxyserver //启动YARN的协议(可以不做)


12)检验hadoop集群
1>验证hdfs
上传文件
hdfs dfs -put wc.txt /
查看目录信息
hdfs dfs -ls / 




# hadoop fs -lsr /
# hadoop fs -ls /
# hadoop fs -rmr /yunwangpan
# hadoop fs -mkdir /mr
# hadoop fs -mkdir /mr/output


# hadoop fs -lsr /
# hadoop fs -put redhat.txt /mr/input    文件上传


# hadoop fs -get /mr/input/xxx.txt /home/data 把/mr/input/下的xxx.txt文件下载到/home/data




2>验证yarn


yarn jar /opt/bigdata/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.1.jar wordcount /mr/input/a.txt /mr/output/out1(来源:/mr/input/redhat.txt 目的:/mr/output/out1)


# hadoop fs -lsr /    复制/mr/output/out1/part-r-00000
# hadoop fs -text /mr/output/out1/part-r-00000

3>查看web监控页面:
查看hdfs:
b1:50070


查看yarn:
b1:8088


查看集群历史服务:
b1:19888




jps进程分布:
[root@h1 ~]# jps
3459 ResourceManager
28692 Jps
3180 DataNode
4408 JobHistoryServer
3073 NameNode
3567 NodeManager
[root@h2 ~]# jps
27643 Jps
2866 DataNode
3188 WebAppProxyServer
27559 NodeManager
2927 SecondaryNameNode
[root@h3 ~]# jps
23179 NodeManager
2832 DataNode
23759 Jps




4、集群的快照、克隆
快照(青春永驻):
对虚拟机的当前状态进行拍照,保存现在状态,对虚拟机进行它操作后可以放回拍照的状态
注意:写注释






克隆:
一克一 或 一个多
分类:
链接克隆:
仅仅是克隆出一个虚拟机的地址,之后使用访问新的虚拟机其实是在使用链接地址


完整克隆:
克隆原有虚拟机的任何信息,之后使用访问新的虚拟机全都是针对新克隆出的虚拟机


完整克隆后的虚拟机需要执行新建虚拟机不需要执行的一步操作(因为把模板机的网卡克隆过来):
进入 :
# vi /etc/udev/rules.d/70-persistent-net.rules
按数字 > 按dd  //实现同时删除多行


5、测试Hadoop
hdfs(Hadoop Ditributed File System)Hadoop分布式文件存储系统的测试:
上传文件到HDFS系统:
hdfs dfs -put 要上传文件的路径 HDFS分布式文件存储系统的路径
hdfs dfs -put /home/hdfs1.txt /
查看文件是否上传成功:
hdfs dfs -ls / //显示当前HDFS文件系统下的文件


hdfs dfs -mkdir 文件夹名  //在hdfs的当前目录下创建文件夹
hdfs dfs -lsr ./ //检验是否在hdfs的当前目录下成功创建文件夹


从hdfs下载文件到本地:
hdfs dfs -get HDFS分布式文件存储系统的路径 hadoop本地的路径




从hdfs下载文件到本地:
hdfs dfs -get 要上传文件的路径 HDFS分布式文件存储系统的路径


6、Hadoop生态圈
1)、HDFS(Hadoop Ditributed File System)Hadoop分布式文件存储系统
源自于Google的GFS论文,HDFS是GFS的克隆版
HDFS是Hadoop中数据存储和管理的基础
它是一个高容错的系统,能够自动解决硬件故障,eg:王建鹏的硬盘损坏,HDFS可以自动修复
可以运行于低成本的通用硬件上(低廉的硬盘,4TB是1200元左右)


一次写入多次读取,不支持修改操作,数据以块切分(按128M切块),按位存储(就近原则)
先下载在修改把新改的加上(一次写入)去在保存(多次读取),修改后之前的数据就没有了


每块数据的大小:
1.0*版本:
64M


2.0*版本:
128M


2)、MapReduce(Hadoop的计算框架)
源于Google的MapReduce


MapReduce是一个分布式的计算框架,用于大量数据的计算(TB-EB),清洗,把计算过程抽象成了两个部分:map和reduce;数据格式:key-value键值对形式存储


Map:会把存储到HDFS上的数据进行计算,生成Key-value格式的数据(作为中间结果)


源数据:
id  name 
1 张三
2 李四
3 张三
4 王五
5 小白


Map计算后的结果(中间结果):
key value
张三 1
李四 2
张三 3
王五 4
小白 5


Reduce:
对中间结果数据进行相同的"键"的所有"值"进行合并规约,得到最终的结果数据




MapReduce适合大量计算机组成的分布式文件的大量数据的计算




3)、YARN(分布式的资源管理器)
YARN是下一代的MapReduce,即MRv2,是在第一代MR基础上演变而来的


YARN是Hadoop2.0*的计算平台,用户可以在YARN上自己编写框架,必须在该环境下运行


YARN是一个通用的计算框架




YARN的组件:
资源管理:
双层资源调度:
4)、HBase(分布式列式文件数据库)
源自于于Google的BigTables论文,发表于2006年,HBase是Google BigTable的克隆


HBase是一个建立在HDFS 上的,面向列的,针对结构化数据、半结构化数据、分布式的数据库


HBase提供了对大量数据的随机、实时读写访问操作,HBase里的数据MapReduce可以对它进行清洗计算


5)、Zookeeper(分布式的协调服务)
也是源于Google的一篇论文:Chubby


解决分布式环境下的数据管理问题:
统一命名,状态同步,集群管理,配置同步


6)、Hive(数据仓库)
FaceBook进行开源,最初用于海量数据(PB级别)结构化数据的统计分析问题


Hive定义了一种类似于SQl的查询语言,Hive把SQl语句转化Map\Reduce任务在Hadoop上操作
便于传统数据的工作人员快速向大数据方向发展


7)、Pig(了解)语言:piglatin
由雅虎开源
是一个数据分析工具
离线分析


8)、Sqoop(数据ETL/同步工具)
主要用于大数据分析工具间的数据导入导出,传统数据库的数据导入到Hadoop的HDFS上


9)、Flume(日志收集工具)
Cloudera开源的日志收集工具,初次数据收集,及离线数据收集


Kafka(日志收集工具)
用于收集实时数据


10)、Mahout(数据挖掘的算法库)
它是机器学习的算法实现,目的是为了帮助开发人员更加快捷方便的创建智能应用程序


Mahout已经涵盖了分类,聚类,推荐引擎,数据挖掘等需要的算法


11)、Oozie(工作流调度器)
集成了Hadoop的堆栈,用于协调多个MapReduce的任务作业的执行


12)、Ambari(安装部署配置管理工具)
创建、管理、监控Hadoop集群,为了防止让Hadoop以及相关的大数据软件更容易使用的一个web工具


13)、Mlib(机器学习库)
Spark Mlib是一个机器学习库,提供了各种各样的算法,eg:分类、回归、协同过滤、聚类等等


14)、Spark(基于内存的计算模型) 处理实时数据
Spark也是Apache项目,被称为"快如闪电的集群计算",目前为止最热、最火的开源的Apache项目


Spark提供了一个更快、更通用的数据处理平台,内存上是Hadoop运行速度的100多倍,磁盘上运行速速提升10倍


15)、Graph(图计算模型)
最早出自于雅虎


16) MongDB ...
7、三大核心四大模块


三大核心:
1)、HDFS(Hadoop Ditributed File System)Hadoop分布式文件存储系统
源自于Google的GFS论文,HDFS是GFS的克隆版
HDFS是Hadoop中数据存储和管理的基础
它是一个高容错的系统,能够自动解决硬件故障,eg:王建鹏的硬盘损坏,HDFS可以自动修复
可以运行于低成本的通用硬件上(低廉的硬盘,4TB是1200元左右)


一次写入多次读取,不支持修改操作,数据以块切分(按128M切块),按位存储(就近原则)


每块数据的大小:
1.0*版本:
64M


2.0*版本:
128M


2)、MapReduce(Hadoop的计算框架)
源于Google的MapReduce


MapReduce是一个分布式的计算框架,用于大量数据的计算,清洗,把计算过程抽象成了两个部分:map和reduce;数据格式:key-value键值对形式存储


Map:会把存储到HDFS上的数据进行计算,生成Key-value格式的数据(作为中间结果)


源数据:
1 张三
2 李四
3 张三
4 王五
5 小白


Map计算后的结果(中间结果):
key value
张三 1
李四 2
张三 3
王五 4
小白 5


Reduce:
对中间结果数据进行相同的"键"的所有"值"进行合并规约,得到最终的结果数据


MapReduce适合大量计算机组成的分布式文件的大量数据的计算




3)、YARN(分布式的资源管理器)
YARN是下一代的MapReduce,即MRv2,是在第一代MR基础上演变而来的
YARN是Hadoop2.0*的计算平台,用户可以在YARN上自己编写框架,必须在该环境下运行
YARN是一个通用的计算框架


四大模块:
Common:是Hadoop的基础设施,为其他模块提供基础服务
HDFS:Hadoop的分布式文件存储系统
MapReduce:一个分布式的高容量,大吞吐量的计算框架
YARN:一个分布式的资源管理框架


8、Hadoop特点
Hadoop优点、缺点:


优点:
高可靠:(就近原则)
按位存储,数据分配就近原则,会把数据分配到离它最近的DataNode,所以值得人们信赖
高扩展:
集群节点可以根据业务需求随时扩展和缩减
高效性:
可以在各个集群集群节点之间动态的移动数据,并且保证集群间各节点之间的动态平衡,因此处理速度非常快
高容错:
Hadoop能够自动保存多个副本(默认3份,可修改),并且能够将失败的任务自动重新分配,解决硬件故障


缺点:
不适合高效存储大量小文件
不适合低延迟的数据访问
不支持多用户的写入和修改操作,支持单用户的写入


9、Hadoop能够干什么?
数据挖掘、收集数据、清洗、计算、数据展现(可视化,BI,eg:热力图)




五、HDFS(Hadoop Distributed File System)


1、HDFS--Hadoop分布式文件存储系统
源自于Google的GFS论文,HDFS是GFS的克隆版
HDFS是Hadoop中数据存储和管理的基础
它是一个高容错的系统,能够自动解决硬件故障,eg:王建鹏的硬盘损坏,HDFS可以自动修复
可以运行于低成本的通用硬件上(低廉的硬盘,4TB是1200元左右)


一次写入多次读取,不支持修改操作,数据以块切分(按128M切块),按位存储(就近原则)


2、HDFS底层架构-分布式文件存储系统
基于物理层存储的分布式(用多台虚拟机来存储咱们的文件)
基于客户端/服务器模式
通常情况下HDFS都会提供容错和备份机制
通常情况下:HDFS都是基于本地系统的文件存储系统




3、分布式文件系统的特点(优缺点)


优点:
高可靠:
按位存储,数据分配就近原则,会把数据分配到离它最近的DataNode,所以值得人们信赖
高扩展:
集群节点可以根据业务需求随时扩展和缩减
高效性:
可以在各个集群集群节点之间动态的移动数据,并且保证集群间各节点之间的动态平衡,因此处理速度非常快
高容错:
Hadoop能够自动保存多个副本(默认3份,可修改),并且能够将失败的任务自动重新分配,解决硬件故障
成本低:


缺点:
不适合高效存储大量小文件
不适合低延迟的数据访问
不支持多用户的写入和修改操作,支持单用户的写入


4、HDFS基本概念:
HDFS是一个分布式文件存储系统(NDFS、GFS)
HDFS是用Java语言实现的、分布式的、可扩展的文件系统
HDFS是Hadoop的三大核心和四大模块之一
HDFS主要用于是应用与海量数据的存储
HDFS是*nix(eg:Linux,Unix)




5、HDFS的前提和设计目标:
硬件问题:
错误检测和快速、自动的恢复是HDFS最核心的架构目标


存储超大文件,存储量可以达到PB、EB级别(单个文件一般至少是百MB以上的!)


数据访问:流式访问(不支持随机访问)




HDFS的简单一致性模型: (重点考)
HDFS需要对它的应用程序实行一次写入、多次读取的访问模式


移动数据比移动计算的成本要高得多
运行在普通的廉价机上


6、HDFS的基本概念
HDFS的基本存储单位:块,块是最小的数据读写单位
Hadoop1.0*默认存储块大小:64M
Hadoop2.0*默认存储块大小:128M(2.0 -- 2.7.2)
2.7.3默认256M


<!--设置块大小,1.*默认64M;2.7.2默认128M;2.73默认256M -->
<property>
<name>dfs.blocksize</name>
<value>268435456</value>
</property>


块大小可以配置文件hdfs-site.xml中修改(参数dfs.blocksize)
块的默认单位:byte
每个块都有自己的全局(唯一)ID
以块为单位在集群服务器上分配存储




块的好处:
一个文件的大小可以大于集群中任一磁盘的容量
块适合于数据备份,提供了容错能力和可用性


7、HDFS 底层架构图--官网


NameNode:
集群的老大,主节点,存放元数据(Metedata)信息
元数据:命名空间,块的生成时间,块的大小,文件目录,最后访问时间等。。。
记录每一数据块在各个DataNode上的位置和副本信息
协调客户端端对文件的访问
NameNode使用事物日志(EditsLog)记录HDFS元数据的变化信息,使用映像文件(FsImageLOg)来存储系统的命名空间,包括:文件映射、文件属性等;
通说检查点(Checkpoint)更新映像文件


SecondaryNameNode(秘书):
NameNode的小秘书,排行老二,协助NameNode
是NameNode的备份,实质上相当于虚拟机的快照


尽量不要把SecondaryNameNode和NameNode放在同一台机器上




DataNode:
小弟,负责存储数据的
一次写入,多次读取(不支持数据修改操作)
数据文件是以块存储的
数据块尽量分布在不同节点的不同DataNode上(保证读取效率的大大提升)




8、HDFS读文件流程
1)先通过客户端调用FileSyStem对象的.open()方法打开HDFS中需要读取的文件
2)FileSyStem通过远程协议调用NameNode,确定要访问的文件的数据块的位置;NameNode返回一个含有数据块的“元数据”信息(即文件的基本信息);然后,DataNode按照NameNode定义的距离值进行排序,如果客户端本身就是一个DataNode,那么会优先从本地的DataNode节点上进行数据读取;
返回一个InputStream给客户端,让其从FSDataInputStream中读取数据,FSDataInputStream接着包装一个DFSInputStream,用来管理DataNode和NameNode的I/O
3)Namenode向客户端返回一个包含数据块信息的地址,客户端会根据创建一个FSDataInputStream,开始对数据进行读取
4)FSDataInputStream根据开始时候存放的位置,连接到离它最近的DataNode,对其上数据进行从头读取操作。读取过程中客户端会反复调用.read()方法,以I/O(流式方式)从DataNode上访问读取数据
5)当读取到Block的最后一块时,FSDataInputStream会关闭掉当前DataNode的链接,然后查找能够读取的下一个Block所在的距离当前最近的DataNode
6)读取完之后调用.close()方法,关闭FSDataInputStream




9、HDFS写文件流程
1)客户端调用FileSyStem的.create()方法来请求创建文件
2)FileSyStem通过NameNode发送请求,创建一个新文件,但此时并不关联其它任何数据块。NameNode进行很多检查保证不存在要创建的文件已经在与HDFS系统当中,同时检查是否有相应的权限来创建这个文件。如果这些检查都已完成,那么NameNode就会记录下来这个新建的文件的信息。FileSyStem就返回一个FSDataOutputStream给客户端让它来写数据。和度的情况一样,FSDataOutputStream将会包装一个DFSOutputStream用于和DataNode以及NameNode进行通讯的。一旦文件创建失败了呢?客户端会接受到一个IOException,表示文件创建失败,停止后续的所有任务
3)客户端开始写数据。FSDataOutputStream把要写入的数据分成块的形式,将其写入到队列中。其中的数据有DataStreamer读取(DataStreamer的职责:让NameNode分配新的块--通过找到合适的DataNode来存储备份的副本数据)这些DataNode组成一条流水线,假设是一个三级流水线,那么里面含有三个节点。此时DataStreamer把数据首先写入到离它最近的DataNode上(第一个节点);然后由第一个节点将数据块写入到第二个节点上;第二个节点继续把数据块传送到第三个节点上
4)FSDataOutputStream维护了一个内部关于write packet的队列,里面存放了等待DataNode确认
无误的packets信息。这个队列称为等待队列。一个packet的信息被移出本队列的前提是当packet流水线中的所有节点确认无误


5)当完成数据写入操作之后,客户端会调用.close()方法,在通知NameNode它写数据完成之前,这个方法将Flush(刷新)残留的packets,并且等待信息确认,NameNode已经知道文件由哪些数据块,通过DataStream询问数据块的分配,所以它在返回成功之前必须要完成配置文件中配置的最小副本数的复制操作




10、HDFS-可靠性
(http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html)


按位存储---就近原则


11、HDFS---容错性
冗rong余副本策略
可以在hdfs-site中指定副本数
所有的数据块都有副本数
DataNode启动时遍历本地文件系统,产生一份hdfs数据块和本地文件系统对应的数据队列进行数据校验,然后汇报给NameNode,NameNode负责管理 (DataNode启动过程中自动检测剩余空间,并汇报给namende)
副本数通常设置为奇数份


<!--副本因子 设置为奇数份(默认3) -->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>




12、HDFS的机架策略
集群的节点一般是放在不同的机架上,机架之间带宽要比机架内带宽要小(这样做的话传输速度)
默认一个机架内存放两个副本,然后再在另一个机架存放一个副本,这样可以防止机架失效数据的丢失,同时它也能够提高带宽利用率


0.17版之前
默认存3个副本
第一个副本放在与客户端同一个机架的距离最近的机器中
第二个副本放在同一个机架距离第一个副本最近的某一台设备中
第三个副本放到不同机架的某一设备中
其它副本随机放置




0.17版之后
默认存3副本
第一个副本放在与客户端同一个机架的设备中
第二个副本放到不同机架的某一设备中
第三个副本放到与第二个副本同一机架的不同设备中
其它副本随机放置


13、心跳机制
心跳 3秒一次
块报告 5分钟一次
完整性报告 1小时


判断DataNode是否死亡
10*3+2*5*60=630秒


NameNode周期性从DataNode接受心跳报告(3s)和快报告(5min)<用来监控集群状态;如果出现错误--自动修复>
NameNode根据快报告验证元数据信息
没有按时发送心跳报告的DataNode会被NameNode标记为死亡状态(宕dang机),不会再给DataNode分配任何I/O请求
如果DataNode失效(死亡或者假死)了,NameNode发现DataNode的副本数降低,低于之前设定的副本因子值(副本数),NameNode在检测出这些数据块丢失之后会在合适的时间自动修复




自动修复数据的原因:
数据副本本身损坏,磁盘故障,修改系统配文件导致副本因子增大,断电等等


14、安全模式(SafeInMode)
1)NameNode启动的时候会先经过一个"安全模式"(保证数据安全)
安全模式下不会产生数据写入操作,因为NameNode验证数据,不支持此操作;支持读取
在此阶段NameNode收集各个DataNode节点的报告,当数据块的最小副本数=配置文件中设置的值时,认为它是"安全模式"
此时退出安全模式,才可以进行数据写入操作


当检测到副本数不足的数据块时,该数据块会被HDFS自动复制直到达到配置文件中设置的最小副本数时停止复制






2)安全模式(SafeInMode)下可以进行的操作:
只能够查询,不支持任何对于数据改动(增加、删除)




3)如何进入安全模式
进入|离开|下载
hdfs dfsadmin -safemode enter|leave|get


进入时的情景:
1、NameNode启动过程中进入
2、手动进入
3、阀值计算公式:已经启动的DataNode节点数/总数
阀值为1的进入安全模式
  <0 永远不安全
0.999和1之间 离开安全模式
0~0.999之间 处于安全模式






15、HDFS的校验和
HDFS的客户端软件实现了对于HDFS文件内容的校验和(Checksum)的检查(提高可靠性)
在文件创建时(调用.creat()),会计算出每个数据块的校验和
校验和会作为一个单独的隐藏文件保存在命名空间NameSpace下
获取文件时会检查数据块对应的校验和是否和隐藏文件(NameSpace下的文件)相同,值相同数据块未发生丢失,值不同数据块丢失,如果损坏或丢失NameNode会自动修复数据块
正在读取数据时发生丢失,不会进行数据修复,不影响数据读取,可以正常操作


16、回收站(类似于windows的回收站,防止误删除操作)
删除文件时,实际上是把它放入了回收站(trash)
如果误删除文件可以进行还原




可以在集群配置文件中设置一个时间阀值,当回收站的文件存放时间达到此时间阀值时会自动清空,彻底删除文件,并且彻底释放原来文件占用的DataNode节点中的数据块


默认是关闭状态,可以通过core-site.xml中添加fs.trash.interval来打开并配置时间阀值,时间以分钟为单位
http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml


17、元数据---保护
映像文件和事物日志是EDITS是NameNode的核心数据。


NameNode会因为副本数的增加而大大降低它的处理速度,但是可以增加它的安全性(即可靠性)


Hadoop1.0*中NameNode依然只有一个,NameNode死掉之后必须手动启动
Hadoop2.0*中集群配置高可用,使其拥有多个NameNode,一个处于Active状态的NameNode节点死掉之后,HA会自动通过SecondaryNamenode启动处于StandBy(准备)状态的NameNode,集群可以正常运行
Hadoop3.0*中拥有多个NameNode,无需进行高可用HA集群配置,StandBy状态的NameNode立刻自动切换为Active状态


18、HDFS常用命令:
命令格式:
hadoop/hdfs/yarn fs -cmd <args>
一)文件操作
1)列出hdfs文件系统中根目录下的目录和文件
hdfs dfs -ls / //列出hdfs下二级目录
hdfs dfs -ls -R /   //列出hdfs的所有文件的详细信息
2)上传文件(hdfs测试命令)
hadoop/hdfs/yarn dfs -put ./test1 ./test
要上传的文件 目标路径的文件


3)文件复制(相当于-put)
-copyFromLocal
hdfs dfs -copyFromLocal 源路径 路径


moveFromLocal
hdfs dfs -moveFromLocal <hdfs src> <local src>




4)将hdfs中的文件下载到本地并且重名
hdfs dfs -get in getin
<hdfs src> <local src>
5)copyToLocal命令
hdfs dfs -copyToLocal <hdfs src> <local src>
作用与-get命令一样


6)删除文档
hdfs dfs -rmr <hdfs file>
hdfs dfs -rm <hdfs file>
hdfs dfs -rm -r <hdfs file>
7) 查看文件内容
hdfs dfs -cat aa
8)建目录
hdfs dfs -mkdir /input
建立多级目录时父目录不存在会报错,目录需要一级一级创建


9)合并多个文件
hdfs dfs -getmerge 多个文件的hdfs路径之间用空格隔开 合并之后的文件名(hadoop本地路径)


二)管理与更新


1)执行基本信息
hdfs dfsadmin -report
2)进入/查看/退出安全模式
hdfs dfsadmin -safemode enter|leave|get


3)添加节点
start-all.sh


4)负载均衡
start-balancer.sh




六、YARN(新的计算框架,资源管理器)
1、什么是YARN?
新的计算框架MRv2,是一个全局的资源管理器,负责整个集群的资源管理和分配,是Master/Slaver模式


2、YARN的组件构成:
调度器(Scheduler)和应用程序管理器(ApplicationMaster)
1)调度器
它仅仅是一个单纯的“调度器”,不参与集群的其它任何操作,负责对各个应用程序的资源进行分配,基本分配单位是一个资源抽象概念"Container",Container封装了内存和CPU等等信息


2)应用程序管理器(ApplicationMaster)AM 当前正在运行任务产生的管理器
应用程序管理器(ApplicationMaster)负责整个系统中所有应用程序,包括:应用程序的提交、与调度器协商资源,向NodeManager发送命令,以启动ApplicationMaster进程,监控ApplicationMaster运行状态并在失败时重新启动它等


3)Container
Container是YARN的资源抽象,Container封装了某个节点内存和CPU,当AM向RM申请资源时,RM为AM返回的资源用Container表示。负责对各个应用程序的资源进行分配,


4)NodeManager(NM)Slaver
是每一个节点上的资源和任务管理器,1>会定时向RM汇报它所在节点的资源使用情况和Container的运行状态;2>可以处理来自AM,RM发送的Container的启动/停止等等命令




5)ResourceManager(RM)Master (老大)
全局资源管理器,负责整个集群的资源管理与分配,RM作为整个集群的资源管理与分配的角色,如果出现单点故障(单个节点宕掉),Hadoop2.4.0版本之前,无法再进行资源管理与分配,Hadoop2.4.0版本出现之后有了HA(高可用),可以增加RM的可用性(出现单点故障不影响RM的运行)


6.历史服务JobhistoryServer
监控hadoop集群的运行状态,如果集群宕机崩溃,历史服务会记录集群崩溃时的信息,存放在历史日志里面
监控任务运行情况及结果


在mapred-site.xml中配置
<!--给程序用的历史服务地址  -->   
<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop01:10020</value>
</property>
<!--给人去实时监控历史服务  -->
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hadoop01:19888</value>
</property>


启动历史服务:
# mr-jobhistory-daemon.sh start historyservice




3.proxyserver协议:失败检测功能
yarn-site.xml中配置proxyserver协议
<property>  
<name>yarn.client.failover-proxy-provider</name>  
<value>org.apache.hadoop.yarn.client.ConfiguredRMFailoverProxyProvider</value>  
</property>
<property>
<name>yarn.web-proxy.address</name>
<value>h1:9989</value>
</property>




启动proxyserver服务
# yarn-daemon.sh start proxyserver  //启动YARN的协议(可以不做)




七.shell
一)简介
1.shell简介
shell本身是用C语言编写的程序
是用户使用Unix/Linux的衔接


shell 既是一种命令语言,而且是一种程序设计语言


注意:shell运行不要用root账户,普通账户授予可读r,可执行x,755;否则可能会对数据造成巨大损坏


2.shell脚本的两种运行方式:
交互式:解释执行用户的命令,用户输入一条,shell就解释执行一条(shell命令)


批处理:用户写完的shell脚本,其中可能包含很多条命令,脚本让它一次执行完,而不是一条一条的再敲命令


eg:
vi a.sh
(vi a.sh文件中写入命令,当执行这个文件所有命令也随之执行)
#!/bin/bash 


hadoop-daemon.sh start namenode
hadoop-daemon.sh start datanode
hadoop-daemon.sh start secondarynamenode
yarn-daemon.sh start resourcemanager
yarn-daemon.sh start nodemanager


3、版本?
bash,sh,ash,csh,ksh


Bourne shell(sh)
Bourne Again shell(bash)
Korn shell(ksh)
C shell(csh)


4.编程语言:编译型语言,解释型语言
编译型语言:C C# C++,Java
源代码>编译>执行
因为转换后的代码接近计算机底层,所以eg:编程时需要指定变量类型,代码量庞大


解释型语言:awk,sed,shell,Python,Perl
源代码>执行
没有编译过程,运行略慢,代码写的过程快,调错快;能轻易实现文本和目录的调用,处理,适合于公司处理大数据


缺点 :运行没有编译型语言块


5.特性
开发容易:可在短时间内完成一个功能强大的好用的脚本
简单:shell是一个脚本语言,弱类型,高级语言;用它可以简洁明了的表达复杂的代码操作
可移植性:脚本本身无需修改就可以在不同的系统上运行


缺点:
shell脚本把代码放进文本里,不安全,全世界人民都能看到


二)使用
1.第一个shell脚本:vi first.sh(/bin/sh)
#!/bin/bash
# author:Lucy
# time:20170628 09:30:30


# #!是一个标记,一定是英文符号,告诉系统用哪一种shell脚本做执行器,如果不写,默认用/bin/sh做执行器
# echo " "把双引号里的东西输出到控制台
# .sh扩展名(不影响脚本运行的)见名知其意
# #表注释
# shell脚本只有单行注释,无多行注释,如果多行注释在代码开头和结尾加{}就可,加{}是把注释的东西当成了一个方法,但是不调用就是注释,不用了就删除{} 一行的开头放#表示对该行注释


echo "你们干嘛呢"


2、shell脚本运行方式:(两种)
1)可执行程序
chmod +x ./first.sh #对该脚本授予可执行权限
./first.sh #执行脚本




注意:是./first.sh,不是first.sh 
2)解释参数(直接运行解释器,参数,无需指定解释器,因为写了也没用)
/bin/sh fir.sh


vi name.shell


echo "What's your name?"
read name
echo "My name is $name!"


3、变量:shell变量的定义、使用、重命名、只读变量、删除变量、变量类型


shell变量是支持自定义的
(1)定义变量
eg:
name="Lucy"


定义变量:变量名="变量值",


注意:
变量名前面不要加$,不需要指定变量类型
变量名和等号之间不能有空格


变量命名规则:字下美人其后数
(字-字母)(下-下划线)(美人-美元符号)(其后-后面)(数-数字)
首字符必须为字母(a-z,A-Z)
中间不能有空格,可以有下划线_
不能使用标点符号
不能用bash里的关键字(用help命令可以查看保留关键字)


(2)使用变量
变量引用:变量名前加 $ 
eg:
name="Lucy"
echo "她叫: $name hahah"




注意:
变量引用:给变量名加{}或者 在$前面加空格,变量名后面加空格;或标点符号;不这样做有时候无法识别变量
(3)变量重命名(已定义的变量可以重新定义)
name="Lucy"
echo ${name}
name="小琪"
echo ${name}
注意:二次赋值不能写成 $name="小琪",引用时候才加 $
(4)只读变量
用readonly命令将普通变量定义成为只读变量,只读变量的值不能修改
eg:(改为只读变量和赋值同时进行正确,否则错误)
#!/bin/bash
readonly MyName="Lucy"
echo ${MyName}




eg:(尝试更改只读变量)
#!/bin/bash
MyName="Lucy"
echo ${MyName}
readonly MyName
MyName="明明"
echo ${MyName}


运行结果:
[root@h data]# ./n1.sh 
Lucy
./n1.sh: line 5: MyName: readonly variable
Lucy


错误:只读变量无法识别
./n1.sh: line 5: MyName: readonly variable
Lucy


(5)删除变量
使用unset命令删除变量;
语法:
unset 变量名
eg:(删除普通变量)
#!/bin/bash


name="小琪"
echo ${name}
unset name
echo ${name}


变量删除之后不能再次使用;unset不能删除只读变量


eg:(删除只读变量)
#!/bin/bash


name="小琪"
echo ${name}
readonly name
echo ${name}
unset name
echo ${name}




运行结果:(不能删除只读变量)
./n3.sh: line 7: unset: name: cannot unset: readonly variable
小琪


(6)变量类型
1局部变量
在脚本和命令中使用,仅仅在当前shell脚本中有效,其他脚本无法使用该局部变量


2环境变量
所有的shell脚本都能访问该变量,环境变量可以自己定义


3 shell变量
shell变量是shell脚本的特殊变量


(7)特殊变量:$$,$0,$1,$*,$@
1)普通变量和特殊变量
普通变量:
字下美人其后数


特殊变量:包含一些其他符号;例如:$$,$0,$1,$*,$@


$表示当前shell脚本的进程号PID 25363
eg:
#!/bin/sh
echo $$
执行结果:
[root@h data]# /bin/sh ./t.sh 
25363


2)特殊变量使用表:
变量 意义
$$ 当前shell脚本的进程(PID)25363
$0 当前shell脚本的文件名
$n 传递给脚本的参数,n可以写成除0以外的参数,eg:$1表第一个参数;$2表第二个参数
$* 以一个字符串的形式显示所有参数
$@ 显示所有参数,加""后就和$*不一样,(下面案例)
$? 上一个命令的退出状态,或者函数的返回值。0表示成功 1表失败  如果上一条不是前两种情况是方法,返回一个方法的返回值
$# 返回传递给脚本的参数个数




eg:
name="小花"
age=“16”
sex=“女”
echo "我是${name},芳龄$age,$sex"
echo $$
echo $0
echo $1
echo $3
echo $*
echo $@
echo "显示所有参数:$@"
echo $?
echo $#
执行结果:这种情况是因为参数不是传进去的
[root@h data]# /bin/sh ./t1.sh 
我是小花,芳龄“16”,“女”
25522
./t1.sh








显示所有参数:
0
0






eg2:vi t2.sh
echo $$
echo $0
echo $1
echo $3
echo $*
echo $@
echo "显示所有参数:$@"
echo $?
echo $#


执行:/bin/sh t2.sh "a" "b" "c" "d"


错误执行方式(传递的参数为 1):
/bin/sh t2.sh "a b c d"
/bin/sh t2.sh "a,b,c,d"


结果:
[root@h data]# /bin/sh t2.sh "a" "b" "c" "d"
25544
t2.sh
a
c
a b c d
a b c d
显示所有参数:a b c d
0
4


3)$*和$@的区别?
eg1:
echo $*
echo $@
执行结果:
[root@h data]# /bin/sh ./t1.sh "a" "b" "c" "d"
a b c d
a b c d


eg2:
echo "--------\例一:$*--------"
for i in "$*";do
echo $i
done


echo "--------\例二:$@--------"
for i in "$@";do
echo $i
done
执行结果:
[root@h data]# /bin/sh ./t2.sh "a" "b" "c" "d"
--------\例一:a b c d--------
a b c d
--------\例二:a b c d--------
a
b
c
d


总结:
相同点:$*和$@:在不使用""时,效果都一样,都是一个参数一个参数来显示,eg:"$1""$2""$3""$4"
不同点:加for循环
$*:把所有参数当成一个参数来显示(一个字符串)
$@:把各个参数分开显示(eg:for循环换行显示i)


4)退出状态
$? 上一个命令的退出状态,或者函数的返回值。0表示成功 1表失败  如果上一条不是前两种情况是方法,返回一个方法的返回值
返回值:可以指定 exit n(n可以随便指定一个数值)


eg:
#!/bin/bash
var1=1
var2=3
var3=$[$var1+$var2]
echo the answer is $var3
echo $?
执行:
[root@h data]# ./t3.sh 
the answer is 4
0




eg:
exit 3
echo $?
执行:
[root@h data]# vi t4.sh
[root@h data]# /bin/sh ./t4.sh 
[root@h data]# echo $?
3


$?还可以表示函数返回值,后面讲函数时讲解


4、shell替换:变量、命令、转义字符的替换
(1)变量替换:
根据变量的状态(是否定义,赋值,为空)来进行替换


 形式 说明
${var} 变量本来的值
${var:-hello} 如果var变量为空或者已经被unset之后,返回hello,但是不改变var的值
${var:+hello} 如果变量var被定义之后,返回hello,但是不改变var的值
${var:=hello} 如果var变量为空或者已经被unset之后,返回hello,并将var的值设置为hello
${var:?message} 如果var变量为空或者已经被unset之后,则将message消息送到标准错误输出界面,主要用来检查变量var是否可以被正常赋值


eg 一:
#!/bin/bash
var=1
unset var
echo ${var:-"变量不会被赋值"}
echo "1--变量值是${var}"


结果:
[root@hw data]# chmod +x ./day10.sh 
[root@hw data]# ./day10.sh 
变量不会被赋值
1--变量值是


eg 二:
var="hello"
unset var
echo ${var:="变量被赋值"}
echo "2--变量值是${var}"


结果:
[root@hw data]# ./day101.sh 
变量被赋值
2--变量值是变量被赋值


eg 三:
var=1
unset var
echo ${var:+"这是默认值,不会被赋值"}
echo "3--变量值是${var}"


结果:
[root@hw data]# /bin/sh day102.sh 
 (null)
3--变量值是


eg 四:
var="hello shell"
echo ${var:+"这是默认值"}
echo "4--变量值是${var}"


echo ${var:?"这是发送的message"}
echo "5--变量值是${var}"


结果:
[root@hw data]# /bin/sh day103.sh 
这是默认值
4--变量值是hello shell
hello shell
5--变量值是hello shell


eg 五:
var="hello shell"
echo ${var:+"这是默认值"}
echo "4--变量值是${var}"


unset var
echo ${var:?"message"}
echo "5--变量值是${var}"


结果:
[root@hw data]# /bin/sh day104.sh 
这是默认值
4--变量值是hello shell
day104.sh: line 6: var: message




(2)命令替换:
☞shell脚本可以先执行命令,将输出结果暂时保存,在合适的地方输出




命令替换的格式:
`命令`


查看并且修改Linux系统时间
查看系统时间:
[root@h data]# date
Tue Jun 27 19:02:52 CST 2017
设置系统时间:
[root@h data]# date -s "20170629 09:09:40"
Thu Jun 29 09:09:40 CST 2017


eg1:
#!/bin/bash
d=`date`
echo "d 是$d"


执行 :  [root@hw data]# ./dd.sh 
d是Thu Jul 27 09:54:42 CST 2017




统计该虚拟机的用户数
[root@h data]# who | wc -l
4


eg2:(把命令执行结果保存到变量中)
#!/bin/bash
user=`who | wc -l`
echo "登录的用户数是$user"


执行 : [root@hw data]# ./b1.sh 
登录的用户数:2


eg3:
ls=`ls | wc`
echo "结果1:$ls"


l=`ls | wc -l`
echo "结果2:$l"


执行 : [root@hw data]# ./b1.sh 
   结果1:      8       8      71
   结果2:8
8行(当前文件夹下文件数) 8个文件 ,71


ls | wc 是统计你这个目录下的文件数目
ls | wc -l是输出第一个结果即250 即文件的数目


(3)转义字符的替换
表达式里含有特殊字符,shell将会进行替换


eg:
var="hello"
echo -e "${var}\nSee you"


结果:
[root@hw data]# /bin/sh b2.sh 
hello
See you


-e表对转义字符进行替换。
不加-e:
hello\nSee you


转义字符 意义
\\ 反斜杠
\a 警报,响铃
\b (BackSpace)删除
\f 换页(FF),下一页
\n 换行
\r 回车
\t (tab)8个字节,一个水平制表符
\v 垂直制表符
-E和不加-e都是禁止对特殊字符进行转义


-n禁止换行,不可以写换行符
eg:
var="hello"
echo -n "${var}\nSee you"
执行:
[root@hw data]# /bin/sh b2.sh 
hello\nSee you[root@hw data]# 




5.Shell运算符:Shell算数运算符,关系与算符,布尔运算符,字符串运算符等


Bash 支持很多运算符,包括算术运算符,关系运算符,布尔运算符,字符串运算符和文件测试运算符


原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如:awk 和 expr ,expr 最常用(expr 是一款表达式计算工具,使用它能完成表达式的求值操作)


eg:求两数和
#!/bin/bash
a=2
b=5
var=`expr $a + $b`
echo "a + b = $var"
结果:
[root@hw data]# /bin/sh b2.sh 
a + b = 7


注:
表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2 这与我们熟悉的大多数编程语言不一样
完整的表达式要被 ``包含,注意这个字符不是常用的单引号,在Esc键下边


(1)算数运算符


算数运算符列表
运算符 说明 举例
+   加法 `expr $a + $b` 结果为 7


-   减法 `expr $a - $b` 结果为 -3


*   乘法 `expr $a \* $b` 结果为 10


/         除法 `expr $a / $b` 结果为 2


%         取余 `expr $a % $b` 结果为 1


=         赋值 a=$b 将把变量 b 的值赋给 a


==       相等,用于比较两个数字,相同则返回 true [  $a == $b ] 返回 true


!= 不相等,用于比较两个数字,不相同则返回 true  [  $a != $b ] 返回 false


注意:
条件表达式要放在方括号之间,并且要有空格,例如 [$a!=$b] 是错误的,必须写成[ $a != $b ]
报错:c2.sh:line 23:[2: command not found]


a=2
b=5


var=`expr $a + $b`
echo "a + b = $var"


var=`expr $b - $a`
echo "b - a = $var"


var=`expr $a \* $b`
echo "a * b = $var"


var=`expr $b / $a`
echo "b / a = $var"


var=`expr $a % $b`
echo "a % b = $var"


a=$b
echo $a


if [ $a == $b ]
then
        echo "a 等于 b"
fi


if [ $a != $b ]
then
        echo "a 不等于 b"
fi


结果
[root@hw data]# /bin/sh b2.sh 
a + b = 7
b - a = 3
a * b = 10
b / a = 2
a % b = 2
5
a 等于 b


注意:
乘号(*)前边必须加反斜杠(\)才能实现乘法运算
if...then...fi 是条件语句


(2)关系运算符


关系运算符列表:
运算符 说明 举例
-eq 检测两个数是否相等,相等返回 true [ $a -eq $b ] 返回 true


-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


关系运算符只支持数字,不支持字符串,除非字符串的值是数字


eg:
#!/bin/sh


a=5
b=10


echo "-----------------< -eq >-----------------------"


if [ $a -eq $b  ]
then
        echo " $a -eq $b:a等于b "
else
        echo " $a -eq $b:a不等于b "
fi


echo "----------------< -ne >------------------------"


if [ $a -ne $b  ]
then
        echo " $a -ne $b:a不等于b "
else
        echo " $a -ne $b:a等于b "
fi


echo "----------------< -gt 大于 >------------------------"


if [ $a -gt $b  ]
then
        echo " $a -gt $b:a大于b "
else
        echo " $a -ge $b:a小于b "
fi


echo "----------------< -lt 小于 >------------------------"


if [ $a -lt $b  ]
then
        echo " $a -lt $b:a小于b "
else
        echo " $a -lt $b:a大于b "
fi


echo "----------------< -ge 大于等于 >------------------------"


if [ $a -ge $b  ]
then
        echo " $a -ge $b:a大于等于b "
else
        echo " $a -ge $b:a小于等于b "
fi




echo "----------------< -le 小于等于 >------------------------"


if [ $a -le $b  ]
then
        echo " $a -le $b:a小于等于b "
else
        echo " $a -le $b:a大于等于b "
fi


结果:
[root@hw data]# /bin/sh b3.sh 
-----------------< -eq >-----------------------
 5 -eq 10:a不等于b 
----------------< -ne >------------------------
 5 -ne 10:a不等于b 
----------------< -gt 大于 >------------------------
 5 -ge 10:a小于b 
----------------< -lt 小于 >------------------------
 5 -lt 10:a小于b 
----------------< -ge 大于等于 >------------------------
 5 -ge 10:a小于等于b 
----------------< -le 小于等于 >------------------------
 5 -le 10:a小于等于b 


(3)布尔运算符


布尔运算符列表
运算符 说明 举例
! 非运算,表达式为true 则返回 false,否则返回 true [ ! false ]返回 true


-o 或运算(or),有一个表达式为true,则返回true [ $a -lt 20 -o $b -gt 100 ] 返回 true


-a 与运算(and),两个表达式都为 true,才返回true [ $a -lt 20 -a $b -gt 100 ] 返回 false


eg:
#!/bin/she
a=5
b=10


echo "-------------<!=>--------------"
if [ $a != $b  ]
then
        echo "$a != $b:a不等于b"
else
        echo "$a == $b:a等于b"
fi


echo "--------------<-a>------------------"
if [ $a -lt 10 -a $b -lt 20 ]
then
        echo "$a -lt 10 -a $b -lt 20 : return true"
else
        echo "$a -lt 10 -a $b -lt 20 : return false"
fi


echo "--------------<-o>------------------"
if [ $a -le 5 -o $b -gt 20 ]
then
        echo "$a -le 5 -o $b -gt 20 : return true"
else
        echo "$a -le 5 -o $b -gt 20 : return false"
fi


结果:
-------------<!=>--------------
5 != 10:a不等于b
--------------<-a>------------------
5 -lt 10 -a 10 -lt 20 : return true
--------------<-o>------------------
5 -le 5 -o 10 -gt 20 : return true




(4)字符串运算符


字符串运算符列表:
运算符 说明 举例
= 检测两个字符是否相等,相等返回true


!= 检测两个字符串是否相等,不想等返回true


-z (zero)检测字符串长度是否为0,为0返回true


-n (lenth)检测字符串长度是否为0,不为0返回true


str 检测字符串是否为空,不为空返回true




eg:
#!/bin/sh


a="hcs"
b="hsch"
c=""


echo "----------------< = >----------------------"
if [ $a = $b  ]
then
        echo "$a = $b :true a 等于 b"
echo "----------------< != >----------------------"
if [ $a != $b  ]
then
        echo "$a != $b :true a 不等于 b"
else
        echo "$a != $b :false a 等于 b"
fi


echo "------------------<-z>----------------------"
if [ -z $a ]
then
        echo "-z $a : string length is zero 字符串长度为0"
else
        echo "-z $a : string length is not zero 字符串长度不为0"
fi


echo "----------------< -n >-----------------------"
if [ -n $a ]
then
        echo "-n $a : string length is not zero 字符串长度不为0"
else
        echo "-n $a : string length is zero 字符串长度为0"
fi


echo "-----------------< str >----------------------------"
if [ $a ]
then
        echo "string is not empty 字符串不为空"
else
        echo "string is empty 字符串长度为空"
fi


if [ $c ]
then
        echo "string is not empty 字符串不为空"
else
        echo "string is empty 字符串长度为空"
fi


执行结果:
[root@hw data]# chmod +x ./b4.sh
[root@hw data]# ./b4.sh 
----------------< = >----------------------
hcs = hsch :false a 不等于 b
----------------< != >----------------------
hcs != hsch :true a 不等于 b
------------------<-z>----------------------
-z hcs : string length is not zero 字符串长度不为0
----------------< -n >-----------------------
-n hcs : string length is not zero 字符串长度不为0
-----------------< str >----------------------------
string is not empty 字符串不为空
string is empty 字符串长度为空




(5)文件测试运算符
文件测试运算符用于检测Unix/Linux文件的各种属性
文件测试运算符列表
操作符 举例 说明
-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。




eg:(变量 file 表示文件“/home/data/a.sh”,它的大小为100字节,具有 rwx 权限。下面的代码,将检测该文件的各种属性:)
#!/bin/sh


file="/home/data/a.sh"


if [ -r $file ]
then
   echo "File has read access"
else
   echo "File does not have read access"
fi


if [ -w $file ]
then


   echo "File has write permission"
else
   echo "File does not have write permission"
fi


if [ -x $file ]
then
   echo "File has execute permission"
else
   echo "File does not have execute permission"
fi


if [ -f $file ]
then
   echo "File is an ordinary file"
else
   echo "This is sepcial file"
fi


if [ -d $file ]
then
   echo "File is a directory"
else
   echo "This is not a directory"
fi


if [ -s $file ]
then
   echo "File size is zero"
else
   echo "File size is not zero"
fi


if [ -e $file ]
then
   echo "File exists"
else
   echo "File does not exist"
fi 




6.shell注释(标准版)
以"#"开头的行就是注释,会被解释器忽略


shell里没有多行注释,只能每一行加一个#号


eg:
#---------------------------------------
#这是一个自动启动集群的脚本,基于Linux的shell书写
#
#功能:自动为集群启动的脚本,可查看jps进程
#特色:全自动启动,不需要输入任何Linux命令
#---------------------------------------
#-------------用户配置区 开始---------------
#
#
#安装包/bin目录,推荐将此脚本放在集群的/bin目录,也可以放其它位置(需先配置/etc/profile)
#应用名,确保和/opt里/bigdata下的hadoop安装包名字一只
#
#-------------用户配置区 结束---------------


如果在开发过程中,遇到大段的代码需要临时注释起来,过一会又取消注释,怎么办?每一行加一个¥符号太费力了,可以把这一段要注释的代码用一对花括号起来,可以定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果


7.shell字符串
字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其他类型好用),字符串可以用单引号,也可以用双引号,也可以不用引号,单双引号的区别跟PHP类似


(1)单引号
eg:
echo "----------单引号----------"
name='jiaomeiqi'
echo '我是$name'
单引号字符串的限制:
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
单引号字符串中不能出现单引号(对单引号使用转义符后也不行)


(2)双引号
eg:
echo '------------双引号---------------'
names="jiaomeiqi"
echo -e "我是$names\t"
双引号的优点:
双引号里可以有变量
双引号里可以出现转义字符


(3)拼接字符串
m="sdasdwf"
na="dwdwe"
echo ${name}${m}${na}




(4)获取字符串长度
string="abcd"
echo ${#string} #输出4


(5)提取子字符串(从0开始计数)
eg:
str="abcde"
echo ${str:0:3}


(6)查找子字符串 
nb="my name is ***"
echo `expr index "$nb" my`
#输出1 (从字符串中第一次出现的位置算起)




8、Shell数组:shell数组的定义、数组长度
Shell在编程方面比Windows批处理强大很多,无论是在循环、运算。


bash支持一维数组(不支持多维数组),并且没有限定数组的大小。
类似于C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。




(1)定义数组
在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为:
    array_name=(value1 ... valuen)


eg:
echo "方法一:"
a_n=(a0 b1 c2 d3)
或者
echo "方法二:"
a_n=(
a0 
b1 
c2 
d3
)


还可以单独定义数组的各个分量:
echo "方法三:"


a_n[0]=a0
a_n[1]=b1
a_n[3]=c3
a_n[4]=d4


可以不使用连续的下标,而且下标的范围没有限制。


(2)读取数组
读取数组元素值的一般格式是:
    ${array_name[index]}
eg1:
#!/bin/sh
a_n=(a0 b1 c2 d3)


echo ${a_n[3]}


结果:
[root@h data]# /bin/sh b1.sh 
d3


eg2:
#!/bin/sh
a_n[0]=a0
a_n[1]=b1
a_n[3]=c3
a_n[4]=d4


echo ${a_n[3]}
结果:
[root@h data]# /bin/sh b.sh 
c3


使用@ 或 * 可以获取数组中的所有元素,eg:
${array_name[*]}
${array_name[@]}


eg3:
#!/bin/sh
a_n=(a0 b1 c2 d3)


echo ${a_n[3]}
echo ${a_n[*]}
echo ${a_n[@]}


结果:
[root@h data]# /bin/sh b1.sh 
d3
a0 b1 c2 d3
a0 b1 c2 d3


(3)获取数组的长度
获取数组长度的方法与获取字符串长度的方法相同
eg:
纯文本复制
# 取得数组元素的个数
eg:
#!/bin/bash
a_n=(a0 b1 c2 d3)
length=${#a_n[@]}
echo $length
# 或者
le=${#a_n[*]}
echo $le


# 取得数组单个元素的长度
lengthn=${#a_n[n]}


9、Shell echo命令
echo是Shell的一个内部指令,用于在屏幕上打印输出指定的字符串。
命令格式:echo arg


可用echo实现更复杂的输出格式控制。


(1)显示转义字符
echo "\"It is a test\""
结果:
"It is a test"


双引号也可以省略。


(2)显示变量
name="OK"
echo "$name It is a test"
结果:
OK It is a test


同样双引号也可以省略。


如果变量与其它字符相连的话,需要使用大括号({ }):
mouth=7
echo "${mouth}-28-2017"
结果:
[root@h data]# /bin/sh d.sh 
7-28-2017


(3)显示换行


echo -e "OK!\n"
echo "It is a test"
输出:
OK!
It is a test




(4)显示不换行
echo -e "OK!\c"
echo "It is a test"
输出:
OK!It si a test


(5)显示结果重定向至文件


eg:
[root@h data]# touch a.log
[root@h data]# ls
a.log


>表示原样输出字符串覆盖原有文件内容
[root@h data]# echo "my name is Lucy" > a.log 
[root@h data]# cat a.log 
my name is Lucy
[root@h data]# echo "how are you" > a.log 
[root@h data]# cat a.log 
how are you


>>表示追加不覆盖
[root@h data]# echo "my name is Lucy" >> a.log 
[root@h data]# cat a.log 
how are you
my name is Lucy


10、shell printf命令:(格式化输出语句)
printf 命令模仿 C 程序库(library)里的 printf() 程序。
标准所定义,因此使用printf的脚本比使用echo移植性好。
printf 使用引用文本或空格分隔的参数,外面可以在printf中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。
默认printf不会像 echo 自动添加换行符,我们可以手动添加 \n。


和 echo 命令一样,printf 命令也可以输出简单的字符串:
eg1:
printf "a b c"
printf "%s \n" "a b c"
结果:
[root@h data]# /bin/sh b.sh 
a b ca b c 
[root@h data]# 




eg2:
printf "a b c"
printf "%s \n" "a b c"
printf "%s \t" "d"


结果1:
d[root@h data]# vi b.sh
[root@h data]# /bin/sh b.sh 
a b ca b c 
d [root@h data]# 


注:
printf 不像 echo 那样会自动换行,必须显式添加换行符(\n)。






printf 命令的语法:
printf  format-string  [arguments...]
format-string 为格式控制字符串,arguments 为参数列表。


printf()在C语言入门教程中包含,功能和用法与 printf 命令类似,请查看:C语言格式输出函数printf()详解


与C语言printf()函数的不同:
printf 命令不用加括号
format-string 可以没有引号(没实现),但最好加上,单引号双引号均可。
参数多于格式控制符(%)时,format-string 可以重用,可以将所有参数都转换。
arguments 使用空格分隔,不用逗号。


eg1:
# format-string为双引号
printf "%d %s\n" 23 "hahaha"
结果:
[root@h data]# /bin/sh c1.sh 
23 hahaha


eg2:
# 单引号与双引号效果一样 
printf '%d %s\n' 23 'hahaha'
结果:
[root@h data]# /bin/sh c.sh 
23 hahaha


eg3:
# 没有引号也可以输出(没实现)---一个参数值可以format-string不加任何符号,两个值及以上不加符号未实现
printf  %s 23 'hahaha'
结果:
[root@h data]# /bin/sh c1.sh 
23hahaha[root@h data]# 




printf %d %s\n 23 hahaha
结果:
[root@h data]# /bin/sh c2.sh 
c2.sh: line 1: printf: %sn: invalid number
c2.sh: line 1: printf: hahaha: invalid 




eg4:
# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
printf  %s 23 'hahaha'
结果:
[root@h data]# /bin/sh c1.sh 
23hahaha[root@h data]# 




printf "%s \n" "abc" "def"
结果:
[root@h data]# /bin/sh a.sh 
abc 
def


printf %s \n abc def
结果:
[root@h data]# /bin/sh a.sh 
nabcdef[root@h data]# 


# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
[root@h data]# printf "%s and %d \n"
 and 0 
 
# 如果以 %d 的格式来显示字符串,那么会有警告,提示无效的数字,此时默认置为 0
[root@h data]# printf %d afdvd dfagdfdav
-bash: printf: afdvd: invalid number
-bash: printf: dfagdfdav: invalid number


[root@h data]# printf %s 1 24 4543 34 23
12445433423[root@h data]# 


注意,根据POSIX标准,浮点格式%e、%E、%f、%g与%G是“不需要被支持”。这是因为awk支持浮点预算,且有它自己的printf语句。这样Shell程序中需要将浮点数值进行格式化的打印时,可使用小型的awk程序实现。然而,内建于bash、ksh93和zsh中的printf命令都支持浮点格式。




11、Shell test命令
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。


(1)数值测试
参数 说明
-eq 等于则为真
-ne 不等于则为真
-gt 大于则为真
-ge 大于等于则为真
-lt 小于则为真
-le 小于等于则为真


eg:
运算符:
num1=100
num2=100
if [ ${num1} -eq ${num2} ]
then
    echo 'The two numbers are equal!'
else
    echo 'The two numbers are not equal!'
fi


数值测试:
num1=100
num2=100
if test ${num1} -eq ${num2}
then
    echo 'The two numbers are equal!'
else
    echo 'The two numbers are not equal!'
fi


结果:
The two numbers are equal!


(2)字符串测试
参数 说明
= 等于则为真
!= 不相等则为真
-z 字符串 字符串长度伪则为真
-n 字符串 字符串长度不伪则为真
eg:
str1="jiaomeiqi"
str2="cdsjkv"·
if test ${str1} = ${str2}
then
    echo 'The two strings are equal!'
else
    echo 'The two strings are not equal!'
fi


结果:
The two strings are not equal!


(3)文件测试
参数 说明
-e 文件名 如果文件存在则为真(exists)
-r 文件名 如果文件存在且可读则为真
-w 文件名 如果文件存在且可写则为真
-x 文件名 如果文件存在且可执行则为真
-s 文件名 如果文件存在且至少有一个字符则为真
-d 文件名 如果文件存在且为目录则为真
-f 文件名 如果文件存在且为普通文件则为真
-c 文件名 如果文件存在且为字符型特殊文件则为真
-b 文件名 如果文件存在且为块特殊文件则为真 


eg:
cd /home/data
if test -e ./a.sh
then
    echo 'The file already exists!'
else
    echo 'The file does not exists!'
fi


结果:
The file already exists!


此外,Shell还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为:“-a”最高,“!”次之,“-o”最低。
eg:
cd /home
if test -e ./data -o ./tmp
then
    echo 'One file exists at least!'
else
    echo 'Both dose not exists!'
fi


结果:
One file exists at least!




12、流程控制语句:
(1)if判断(结束用fi)


if判断:
语法:
if 条件
then 输出
fi


eg:
nu=2
nuu=2
if [ ${nu} -eq ${nuu} ]
then
        echo `expr ${nu} \* ${nuu}`
fi




if-else判断:
语法:
if  条件
then 输出
else 输出
fi


eg:
cd /home/data
if test -e ./a.sh
then
    echo 'The file already exists!'
else
    echo 'The file does not exists!'
fi


if then- else -if else判断:
if  条件
then 输出
elif 条件
then 输出
else 输出
fi


eg 1:
#!/bin/bash
a=1
b=2
if [ $a == $b ]
then
echo "a等于b"
elif [ $a -lt $b ]
then
echo "a小于b"
elif [ $a -gt $b ]
then
echo "a大于b"
else
echo "不符合以上所有判断"
fi


结果:
[root@h data]# vi a.sh
[root@h data]# chmod +x ./a.sh 
[root@h data]# ./a.sh 
a小于b




eg 2:(if与test命令结合使用) ----- test测试:数值测试可用[];字符串测试必须用{}
n1=$[2*4]
n2=$[5+3]
if test $[n1] -eq $[n2]
then
echo "n1等于n2"
else
echo "两数字不一样"
fi


(2)for循环
语法:
for variable in item1 item2 item3....
do
输出
输出
....
输出
done


一行:
for variable in item1 item2 item3....; do 输出;输出;....;输出;done
in后面可以跟任何替换、字符串、文件








eg:
echo "--------\例一:$*--------"
for i in "$*";do
echo $i
done


echo "--------\例二:$@--------"
for i in "$@";do echo $i;done
执行结果:
[root@h data]# /bin/sh ./t2.sh "a" "b" "c" "d"
--------\例一:a b c d--------
a b c d
--------\例二:a b c d--------
a
b
c
d


无限循环
for((;;))


(3)while
通常用于处理大量的命令,或是从输入文件中读取数据信息;(命令通常指测试条件)


格式:
while 判断条件
do
输出
done




eg 1:
#!/bin/bash
i=1
while(($i<=5))
do
echo "$i"
let "i++"
done




无限循环:
while true
do
输出
done


eg 2:
echo "What's your name?"
while read name
do
echo "My name is ${name}!"
done


(4)until
until 循环执行一系列命令直至条件为true时停止,until循环与while循环 循环在处理方式上刚好相反,一般while循环由于until循环,但在某些时候,也只是极少数情况下,until循环更加有用


语法:(循环至少执行一次)
until 条件
do
输出
done


条件:一般为条件表达式,如果返回值为false,则继续执行循环体内的语句,否则跳出循环


eg:(使用until命令输出数字)
echo "-----------until循环-------------------"
a=3
until [ ! $a -lt 10 ]
do
        echo "${a}"
        a=`expr $a + 1`
done


echo "-----------------while循环----------------------"


b=5
while((${b}<=10))
do
        echo "${b}"
        b=`expr ${b} + 1`
done


结果:
[root@hw data]# /bin/sh b9.sh 
-----------until循环-------------------
3
4
5
6
7
8
9
-----------------while循环----------------------
5
6
7
8
9
10


   
(5)case
语法:
case 值 in
模式1)
输出1
输出2
输出3
输出...
模式2)
输出1
输出2
输出3
输出...
esac




eg:
echo "输入1到3之间的数字:"
echo "亲,输入的数字是:"
read num
case $num in
1)
echo "你选择了1";;
2)
echo "你选择了2";;
3)
echo "你选择了3";;
*)
echo "你没有输入1到3之间的数字";;
esac


结果:
[root@hw data]# /bin/sh b10.sh 
输入1到3之间的数字:
亲,输入的数字是:
1
你选择了1
[root@hw data]# /bin/sh b10.sh 
输入1到3之间的数字:
亲,输入的数字是:
5
你没有输入1到3之间的数字




(6)跳出循环
break和continue
break命令
跳出所有循环(终止执行后面操作)
continue命令
不跳出所有循环,仅仅跳出当前循环


eg:
#!/bin/bash
while true
do
echo "输入1到3之间的数字:"
echo "亲,输入的数字是:"
read num
case $num in
1|2|3)
echo "你选择了$num";;
*)
echo "你没有输入1到3之间的数字";
continue
echo "over!"
;;
esac
done


结果:
[root@hw data]# /bin/sh b10.sh 
输入1到3之间的数字:
亲,输入的数字是:
1
你选择了1
输入1到3之间的数字:
亲,输入的数字是:
5
你没有输入1到3之间的数字
输入1到3之间的数字:
亲,输入的数字是:


#!/bin/bash
while true
do
echo "输出1~5之间的数字:"
echo "请输入输出的数字是"
read num
case $num in
1|2|3|4|5)
echo "你选择了$num";;
*)
echo "只能输入1~5之间的数"
continue
echo "over!"
;;
esac
done


6、shell文件包含、引用
eg1:/home/data/a.sh
vi b.sh
#!/bin/bash
. /home/data/a.sh
source /home/data/a.sh




eg2:cd /home/data
a.sh


. ./a.sh
source ./a.sh


.加空格 文件路径/文件名
source加空格 文件路径/文件名




13、Shell函数:Shell函数返回值、删除函数、在终端调用函数


(1)shell函数作用:
函数的作用:
可以让我们将一个复杂功能划分成若干模块,
让程序结构更加清晰,
代码重复利用率更高。




像其他编程语言一样,Shell 也支持函数。
Shell 函数必须先定义后使用。


(2)定义shell函数:
Shell 函数的定义格式如下:
function_name () {
    list of commands
    [ return value ]
}
如果愿意,也可在函数名前加上关键字 function:
function function_name () {
    list of commands
    [ return value ]
}


(3)shell函数返回值:
函数返回值可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值。


Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。
如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。


如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。


eg1:
#!/bin/bash


# Define(确定) your function here
Hello () {
a="hello shell!"
   echo $a
}
# Invoke(调用) your function
Hello


运行结果:
[root@h data]# chmod +x ./a.sh 
[root@h data]# ./a.sh 
hello shell!


调用函数只需要给出函数名,不需要加括号。




eg2:(一个带有return语句的函数)
#!/bin/bash
funWithReturn(){
    echo "求两数之和"
    echo -n "输入第一个数字: "
    read aNum
    echo -n "输入第二个数字: "
    read anotherNum
    echo "这两个数字是 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
# Capture value returnd by last command(捕获上一个命令返回的值)


ret=$?
echo "The sum of two numbers is $ret !"


运行结果:(函数返回值在调用该函数后通过 $? 来获得)
[root@h data]# /bin/sh a1.sh 
求两数之和
输入第一个数字: 5
输入第二个数字: 6
这两个数字是 5 和 6 !
The sum of two numbers is 11 !




eg3:(一个函数嵌套的例子):
#!/bin/bash
# Calling one function from another(从另一个调用一个函数)
num_one () {
num_two
  echo "http://write.blog.csdn.net/postlist"
}
num_two () {
   echo "我的博客是:"
}
num_one
运行结果:
[root@h data]# /bin/sh b.sh 
我的博客是:
http://write.blog.csdn.net/postlist




(4)删除shell函数:
像删除变量一样,删除函数也可以使用 unset 命令,不过要加上 .f 选项,如下所示:
$unset .f function_name


(5)终端调用函数
直接从终端调用函数?
可以将函数定义在主目录下的 .profile 文件,这样每次登录后,在命令提示符后面输入函数名字就可以立即调用。




14、Shell函数参数
在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...


变量 意义
$n 传递给脚本的参数,n可以写成除0以外的参数,eg:$1表第一个参数;$2表第二个参数
$* 以一个字符串的形式显示所有参数
$@ 显示所有参数,加""后就和$*不一样,(下面案例)
$? 上一个命令的退出状态,或者函数的返回值。0表示成功 1表失败  如果上一条不是前两种情况是方法,返回一个方法的返回值
$# 返回传递给脚本的参数个数


eg(带参数的函数示例):
#!/bin/bash
funWithParam(){
    echo "第一个参数是: $1 !"
    echo "第二个参数是: $2 !"
    echo " 第10个参数是:$10 !"
    echo " 第10个参数是:${10} !"
    echo " 第十一个参数是:${11} !"
    echo " 返回传递给脚本的参数个数: $# !"  # 参数个数
    echo "以一个字符串的形式显示所有参数: $* !"  # 传递给函数的所有参数
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73


运行脚本:
结果1:
[root@h data]# chmod +x ./c.sh 
[root@h data]# ./c.sh 
第一个参数是: 1 !
第二个参数是: 2 !
 第5个参数是:5 !
 第5个参数是:5 !
 第十一个参数是:73 !
 返回传递给脚本的参数个数: 11 !
以一个字符串的形式显示所有参数: 1 2 3 4 5 6 7 8 9 34 73 !


结果2:
[root@h data]# ./c.sh 
第一个参数是: 1 !
第二个参数是: 2 !
第10个参数是:10 !
第10个参数是:34 !
第十一个参数是:73 !
返回传递给脚本的参数个数: 11 !
以一个字符串的形式显示所有参数: 1 2 3 4 5 6 7 8 9 34 73 !




注意:
$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。


15、Shell输入输出重定向
Unix 命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示。一般情况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器。




(1)输出重定向
命令的输出不仅可以是显示器,还可以很容易的转移向到文件,这被称为输出重定向。


命令输出重定向的语法为:(追加覆盖)
command > file
这样,输出到显示器的内容就可以被重定向到文件。


eg1:(打开a.log文件,可以看到下面的内容)
[root@h data]# cat a.log 
vbadfvbf
vbsjv
VDSJK


eg2:(输出重定向会覆盖文件内容)
[root@h data]# echo line 1 > a.log 
[root@h data]# cat a.log 
line 1


追加不覆盖,用 >> 追加到文件末尾
command >> file
eg:
[root@h data]# echo line 2 >> a.log
[root@h data]# cat a.log
line 1
line 2




(2)输入重定向
和输出重定向一样,Unix 命令也可以从文件获取输入,语法为:
command < file
这样,本来需要从键盘获取输入的命令,会转移到文件读取内容。


注意:
输出重定向是大于号(>),输入重定向是小于号(<)。


eg1:(计算 a.log 文件中的行数)
[root@h data]# wc -l a.log 
2 a.log




eg2:(将输入重定向到 a.log 文件)
[root@h data]# wc -l < a.log 
2


注意:
上面两个例子的结果不同:
eg1--会输出文件名;eg2--不会因为它仅仅知道从标准输入读取内容。


16、shell文件包含、引用
像其他语言一样,Shell 也可以包含外部脚本,将外部脚本的内容合并到当前脚本。


Shell 中包含脚本可以使用:
. filename

source filename


两种方式的效果相同,简单起见,一般使用点号(.),但是注意点号(.)和文件名中间有一空格。
eg:
[root@h data]# vi a.sh
echo "你叫什么名字?"
结果:
[root@h data]# /bin/sh a.sh 
你叫什么名字?


[root@h data]# vi b.sh
echo "我是:焦美琪"
结果:
[root@h data]# /bin/sh b.sh 
我是:焦美琪


[root@h data]# vi b.sh
# source ./a.sh
. ./a.sh
echo "我是:焦美琪"
结果:
[root@h data]# /bin/sh b.sh 
你叫什么名字?
我是:焦美琪


eg1:/home/data/a.sh
vi b.sh
#!/bin/bash
. /home/data/a.sh
source /home/data/a.sh




eg2:cd /home/data
a.sh


. ./a.sh
source ./a.sh


.加空格 文件路径/文件名
source加空格 文件路径/文件名


八、AWK
1、简介
主要用来处理文本数据,处理效率高(于shell),代码简洁高效,绝对不会遇到内存溢出


2、命令处理模式:
按行处理,一行一行执行(和shell一样)
3、命令格式:
awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
-F指定分隔符 -f调用脚本 -v定义变量 var=value
'  '          引用代码块(''单引号)
BEGIN   初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
//           匹配代码块,可以是字符串或正则表达式
{}           命令代码块,包含一条或多条命令
;        多条命令使用分号分隔
END      结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息




4、awk正则:
$0           当前所在行
$n           每行第n个字段(打印列) n可以换成任一正整数
NF          字段数量变量
NR          每行的记录号,多文件记录递增
FNR        与NR类似,不过多文件记录不递增,每个文件都从1开始
\t            制表符
\n           换行符
FS          BEGIN时定义分隔符
RS       输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
~            匹配,与==相比不是精确比较
!~           不匹配,不精确比较
==         等于,必须全部相等,精确比较
!=           不等于,精确比较
&&      逻辑与
||             逻辑或
+            匹配时表示1个或1个以上
/[0-9][0-9]+/   两个或两个以上数字
/[0-9][0-9]*/    一个或一个以上数字
FILENAME 文件名
OFS      输出字段分隔符, 默认也是空格,可以改为制表符等
ORS        输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
-F'[:#/]'   定义三个分隔符
-F":#/"


5、awk调用方式
1.命令行方式
awk [-F  field-separator]  'commands'  input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一般通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk


3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的


6、操作
最近登录账户的查看:(-F指定分隔符仅支持:不加"",其它分隔符不加""全部不识别)
last -n 2 | awk  '{print $1}' //print打印指定内容


awk '{print}'  /etc/passwd 等于 awk '{print $0}'  /etc/passwd 等于 cat /etc/passwd


awk '{print " "}' /etc/passwd //不输出passwd的内容,而是输出相同个数的空行,进一步解释了awk是一行一行处理文本


awk '{print "a"}'   /etc/passwd //输出相同个数的a行,一行只有一个a字母
awk -F":" '{print $1}'  /etc/passwd
awk -F: '{print $1}'  /etc/passwd
awk -F'[:]' '{print $1}'  /etc/passwd




awk -F"/" '{print $2}'  /etc/passwd
awk -F: '{print $1; print $2}'   /etc/passwd(换行显示) 等于 awk -F: '{print $1, $2}'(不换行)   /etc/passwd//将每一行的前二个字段,分行输出,进一步理解一行一行处理文本
awk  -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd //指定以tab键分隔第1,3,6个字段 OFS指定分隔符


7、变量:-v
(1)内置变量
ARGC               命令行参数个数
ARGV               命令行参数排列
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                浏览文件的记录数
FS                 设置输入域分隔符,等价于命令行 -F选项
NF                 浏览记录的域的个数
NR                 已读的记录数
OFS                输出域分隔符-F
ORS                输出记录分隔符
RS                 控制记录分隔符


统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
#awk  -F '/'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:29,columns:6,linecontent:saslauth:x:498:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin
filename:/etc/passwd,linenumber:30,columns:6,linecontent:postfix:x:89:89::/var/spool/postfix:/sbin/nologin
filename:/etc/passwd,linenumber:31,columns:6,linecontent:pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
filename:/etc/passwd,linenumber:32,columns:6,linecontent:sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
filename:/etc/passwd,linenumber:33,columns:4,linecontent:tcpdump:x:72:72::/:/sbin/nologin
打印:文件名,行数,字段数,当前行内容
awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
awk  -F ':'  '{printf("filename:%s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
awk  -F ':'  '{printf "filename:"FILENAME",linenumber:"NR",columns:"NF",linecontent:"$0"\n"}' /etc/passwd




%10s:
输入时,%10s表示最多接受10个字符,多余的忽略;
输出时,%10s表示字符串长度不足10个时,左边补空格,保证占10个字节位置,10个及以上原样输出.


print和printf
awk中同时提供了print和printf两种打印输出的函数。
print函数的参数:变量、数值或者字符串。(字符串必须用""引用,参数用,分隔。如果没有, ,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。)
printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。


(2)自定义变量:
统计虚拟机/etc/passwd用户数量:
awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd


8、awk实现wordcount(词频统计)案例
vi a.log
my name is hahah .
14 years old




运行方式一:
vi wc.awk


{
  for (i = 1; i<=NF; i++)
    freq[$i]++
}
END{
  for (word in freq)
    printf "%s%d\n",word,freq[word]
}
运行:
awk -f wc.awk a.log




运行方式二:
vi wordcount_awk.sh
#!/bin/sh
awk -F " " '{
  for (i = 1; i<=NF; i++)
    freq[$i]++
}
END{
  for (word in freq)
    printf "%s%d\n",word,freq[word]
}' $1


chmod u+x wordcount_awk.sh
./wordcount_awk.sh f.txt


9、打印九九乘法表
seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'
三、sed
1、简介
sed 是一种在线编辑器,流编辑器,它是文本处理中非常中的工具,能够完美的配合正则表达式使用
一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),然后用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。然后循环以上操作。
文件内容并没有 改变,除非你使用重定向存储输出。
Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。


2、正则:
^ 匹配行开始,如:/^sed/匹配所有以sed开头的行
$ 匹配行结束,如:/sed$/匹配所有以sed结尾的行
. 匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d
* 匹配0个或多个字符,如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行
[] 匹配一个指定范围内的字符,如/[ss]ed/匹配sed和Sed
[^] 匹配一个不在指定范围内的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行
\(..\) 匹配子串,保存匹配的字符,如s/\(love\)able/\1rs,loveable被替换成lovers
& 保存搜索字符用来替换其他字符,如s/love/**&**/,love这成**love**
\< 匹配单词的开始,如:/\ 匹配单词的结束,如/love\>/匹配包含以love结尾的单词的行
x\{m\} 重复字符x,m次,如:/0\{5\}/匹配包含5个0的行
x\{m,\} 重复字符x,至少m次,如:/0\{5,\}/匹配至少有5个0的行
x\{m,n\} 重复字符x,至少m次,不多于n次,如:/0\{5,10\}/匹配5~10个0的行


3、sed使用参数
sed [options] 'command' file(s)
sed [options] -f scriptfile file(s)


选项与参数:
-n :使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。
-e :直接在命令列模式上进行 sed 的动作编辑;
-f :直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 sed 动作;
-r :sed 的动作支持的是延伸型正规表示法的语法。(默认是基础正规表示法语法)
-i :直接修改读取的文件内容,而不是输出到终端。


动作说明: [n1[,n2]]function
n1, n2 :不见得会存在,一般代表『选择进行动作的行数』,举例来说,如果我的动作是需要在 10 到 20 行之间进行的,则『 10,20[动作行为] 』


function:
a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d :删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行~
s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!






4、以行为单位的新增/删除:
将 /etc/passwd 的内容列出并且列印行号,同时,请将第 2~5 行删除!


# nl /etc/passwd | sed '2,5d'


sed 的动作为 '2,5d' ,那个 d 就是删除!因为 2-5 行给他删除了,所以显示的数据就没有 2-5 行罗~ 另外,注意一下,原本应该是要下达 sed -e 才对,没有 -e 也行啦!同时也要注意的是, sed 后面接的动作,请务必以 '' 两个单引号括住喔!


只要删除第 2 行


# nl /etc/passwd | sed '2d' 
 


要删除第 3 到最后一行


# nl /etc/passwd | sed '3,$d' 
 


在第二行后(亦即是加在第三行)加上『2a 啊』字样!


# nl /home/data/a.log | sed '2a 啊?'




那如果是要在第二行前


# nl /etc/passwd | sed '2i drink tea' 
如果是要增加两行以上,在第二行后面加入两行字,例如『Drink tea or .....』与『drink beer?』




# nl /etc/passwd | sed '2a Drink tea or ......\


每一行之间都必须要以反斜杠『 \ 』来进行新行的添加喔!所以,上面的例子中,我们可以发现在第一行的最后面就有 \ 存在。




5、以行为单位的替换与显示:
将第2-5行的内容取代成为『No 2-5 number』呢?


# nl /home/data/a.log | sed '2,5c No 2-5 number'
通过这个方法我们就能够将数据整行取代了!


 


仅列出 /home/data/f.txt 文件内的第 5-7 行


# nl /home/data/f.txt | sed -n '5,7p'
可以透过这个 sed 的以行为单位的显示功能, 就能够将某一个文件内的某些行号选择出来显示。


 
6、数据的搜寻并显示:


搜索 /etc/passwd有root关键字的行


nl /etc/passwd | sed '/root/p'
如果root找到,除了输出所有行,还会输出匹配行。
 


使用-n的时候将只打印包含模板的行:
[root@h data]# nl /etc/passwd | sed -n '/root/p'
     1 root:x:0:0:root:/root:/bin/bash
    11 operator:x:11:0:operator:/root:/sbin/nologin


7、数据的搜寻并删除
删除/etc/passwd所有包含root的行,其他行输出


nl /etc/passwd | sed  '/root/d'


#第一行的匹配root已经删除了
 


8、数据的搜寻并执行命令
找到匹配模式eastern的行后,


搜索/etc/passwd,找到root对应的行,执行后面花括号中的一组命令,每个命令之间用分号分隔,这里把bash替换为blueshell,再输出这行:


[root@h data]# nl /etc/passwd | sed -n '/root/{s/bash/blueshell/;p}'
     1 root:x:0:0:root:/root:/bin/blueshell
    11 operator:x:11:0:operator:/root:/sbin/nologin


如果只替换/etc/passwd的第一个bash关键字为blueshell,就退出
[root@h data]# nl /etc/passwd | sed -n '/bash/{s/bash/blueshell/;p;q}'
     1 root:x:0:0:root:/root:/bin/blueshell
最后的q是退出。


 


9、数据的搜寻并替换
除了整行的处理模式之外, sed 还可以用行为单位进行部分数据的搜寻并取代。基本上 sed 的搜寻与替代的与 vi 相当的类似!他有点像这样:


sed 's/要被取代的字串/新的字串/g'
 


先观察原始信息,利用 /sbin/ifconfig 查询 IP


# /sbin/ifconfig eth0


本机的ip是192.168.1.100。


 


将 IP 前面的部分予以删除


# /sbin/ifconfig eth0 | grep 'inet addr' | sed 's/^.*addr://g'
192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
接下来则是删除后续的部分,亦即: 192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0




将 IP 后面的部分予以删除


# /sbin/ifconfig eth0 | grep 'inet addr' | sed 's/^.*addr://g' | sed 's/Bcast.*$//g'
192.168.1.100
 


10、多点编辑


my name is hahah .
14 years old
恩恩
how
old are
 you?


how
what
wherre
wherre
where




一条sed命令,删除/etc/passwd第三行到末尾的数据,并把old替换为年龄
nl /home/data/f.txt | sed -e '3,$d' -e 's/old/年龄/'


-e表示多点编辑,第一个编辑命令删除/home/data/f.txt第三行到末尾的数据,第二条命令搜索old替换为年龄。




11、直接修改文件内容(危险动作一定不要对Linux下的/etc、/bin、/usr、/boot等系统自带目录进行操作)


sed 可以直接修改文件的内容,不必使用管道命令或数据流重导向! 不过,由於这个动作会直接修改到原始的文件,所以请你千万不要随便拿系统配置来测试! 我们还是使用下载的 regular_express.txt 文件来测试看看吧!


利用 sed 将 regular_express.txt 内每一行结尾若为 . 则换成 !


# sed -i 's/\.$/\!/g' regular_express.txt
 


利用 sed 直接在 regular_express.txt 最后一行加入『# This is a test』


# sed -i '$a # This is a test' regular_express.txt
由於 $ 代表的是最后一行,而 a 的动作是新增,因此该文件最后新增『# This is a test』!


sed 的『 -i 』选项可以直接修改文件内容,这功能非常有帮助!举例来说,如果你有一个 100 万行的文件,你要在第 100 行加某些文字,此时使用 vim 可能会疯掉!因为文件太大了!那怎办?就利用 sed 啊!透过 sed 直接修改/取代的功能,你甚至不需要使用 vim 去修订!
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值