1.前期准備
1.1系統和yum源鏡像准備
需要的條件:
① 至少三台剛裝上Centos7.0系統的物理機或者虛擬機;
② CentOS-7.0-x86_64-bin-DVD1.iso鏡像,用於制作本地yum源;
注意:本文三台物理機或虛擬機的操作系統鏡像是CentOS-7-x86_64-Minimal-1804.iso。
用於制作本地yum源的CentOS-7.0-x86_64-bin-DVD1.iso鏡像默認存放於第一節點node1的/opt/system下
1.2 配置文件host_ip.txt和frames.tx准備
host_ip.txt文件為集群ip、hostname、root賬號密碼配置;而frames.txt為所需要安裝的軟件配置說明,其中false為不安裝,true為安裝
host_ip.txt內容為:
192.168.187.201 node1 root hadoop 192.168.187.202 node2 root hadoop 192.168.187.203 node3 root hadoop
frames.txt內容為:
jdk-8u181-linux-x64.tar.gz true scala-2.11.0.tgz true hadoop-2.7.6.tar.gz true hbase-2.0.1-bin.tar.gz true apache-hive-2.3.3-bin.tar.gz true zookeeper-3.4.13.tar.gz true spark-2.3.1-bin-hadoop2.7.tgz true kafka_2.11-1.1.1.tgz true
1.3 安裝軟件准備
需要在官網上下載frames.txt所列的軟件安裝包,可以自行下載。
這里默認所有的軟件安裝包放在第一節點node1的/opt/frames目錄下,下面涉及軟件部分的shell操作都會根據/opt/frames/目錄下是否有該軟件再進行自動安裝。
1.4 shell命令文本准備
以下shell文本文件,以及host_ip.txt和frames.txt文件,都默認放置在第一節點node1的/home/hadoop/automaticDeploy目錄下,如圖:
2.模塊化自動安裝部署
注意:以下所有shell命令的執行,都需要以root用戶執行
模塊化自動安裝部署包括IP地址設置、機器名hostname修改、host配置文件修改、關閉防火牆/SELINUX、添加bigdata用戶名、配置yum源、配置SSH無密碼登錄、配置JDK環境、配置Scala環境共9個模塊。
2.1 集群中每台機器IP地址的設置
集群中每台機器首先需要設置IP地址,保證機器與機器之間可以直接通過ip地址訪問。
IP地址設置shell命令文件editIpAddr.sh代碼如下:
#! /bin/bash ################ #針對Centos-7.0 ################ #處理涉及到IP地址設置的網絡文件,備份並創建新的 function doWithNetworkFile() { #1.查找/etc/sysconfig/network-scripts/目錄下是否存在ifcfg-ens33文件,存在則重命名為.bak結尾的 fileResult=`find /etc/sysconfig/network-scripts/ -name "ifcfg-ens33"` if [[ $fileResult != "" ]] then #2.創建一個ifcfg-ens33文件用於配置網絡設置 result=`find /etc/sysconfig/network-scripts -wholename $fileResult.bak` if [[ -z $result ]] then mv $fileResult $fileResult.bak fi cp $fileResult.bak $fileResult else touch /etc/sysconfig/network-scripts/ifcfg-ens33 fi } #配置ip地址 function configureIpAddr() { ip=$1 gateway=$2 fileUrl=/etc/sysconfig/network-scripts/ifcfg-ens33 #1.把ifcfg-ens33文件非#開頭的行注釋掉 sed -i 's/^[^#]/#&/' $fileUrl UUID=`grep "^#UUID=*" $fileUrl | head -1` #2.配置內網IP地址 #連接類型 echo "TYPE=Ethernet" >> $fileUrl #靜態IP echo "BOOTPROTO=static" >> $fileUrl echo "DEFROUTE=yes" >> $fileUrl echo "IPV4_FAILURE_FATAL=no" >> $fileUrl #IPV6關閉 echo "IPV6INIT=no" >> $fileUrl #配置名字 echo "NAME=ens33" >> $fileUrl #唯一標識 echo "${UUID:1}" >> $fileUrl #網卡名稱 echo "DEVICE=ens33" >> $fileUrl #開機即啟動網絡 echo "ONBOOT=yes" >> $fileUrl #IP地址 echo "IPADDR=$ip" >> $fileUrl echo "PREFIX=24" >> $fileUrl #網絡掩碼 echo "NETMASK=255.255.255.0" >> $fileUrl #網關 echo "GATEWAY=$gateway" >> $fileUrl } function editIpAddr() { ip=$1 gateway=$2 #處理涉及到IP地址設置的網絡文件,備份並創建新的 doWithNetworkFile #在/etc/sysconfig/network-scripts/ifcfg-ens33上設置IP地址 configureIpAddr $ip $gateway #重啟網絡服務 service network restart } ip=$1 gateway=$2 editIpAddr $ip $gateway
分別在三台機器上以root用戶執行如下命令:
/home/hadoop/automaticDeploy/systems/editIpAddr.sh 192.168.187.*** 192.168.187.2
注意:
①網關192.168.187.2需要通過 route -n 命令(CentOS7以上使用)查看,如圖:
②不同機器的ip地址是不一樣的,這里指IP地址的前三個數值是一樣,前三個數值與網關的前三個數值是一致的;只有最后一個***是根據需求設置,一般在0~255之間。這里我假定三個節點node1、node2、node3的IP分別為192.168.187.201,192.168.187.202,192.168.187.203。
2.2 修改機器名hostname
changeHostname.sh代碼如下:
#! /bin/bash #修改機器名hostname function changeHostname() { hostname=$1 #echo "change the hostname $1" egrep "^HOSTNAME=" /etc/sysconfig/network >& /dev/null if [ $? -eq 0 ] then #存在則刪除舊的hostname sed -i "/^HOSTNAME=/d" /etc/sysconfig/network fi #添加新的hostname echo "HOSTNAME=$hostname" >> /etc/sysconfig/network #echo "change the hostname $1 successfully" } #獲取參數 node=$1 if [ -z $node ] then echo "參數為空,請輸入參數node1,node2,node3..." else changeHostname $node fi
以root用戶執行如下命令,$hostname為參數傳值,設為node1、node2、node3....
/home/hadoop/automaticDeploy/systems/changeHostname.sh $hostname
2.3 host配置文件修改
addClusterIps.sh代碼如下:
#! /bin/bash #添加Ip、hostname到/etc/hosts文件里面 function addIpToHostFile() { ip=$1 hostname=$2 #查詢$ip是否存在於/etc/hosts里面 egrep "^$ip" /etc/hosts >& /dev/null if [ $? -eq 0 ] then #$?是上一個程序執行是否成功的標志,如果執行成功則$?為0,否則不為0,存在則先把就的ip設置刪除掉 sed -i "/^$ip/d" /etc/hosts fi #把ip、hostname添加到/etc/hosts中 echo "$ip $hostname" >> /etc/hosts } #執行ssh免密登錄之前,hosts文件里面需要存儲每台機器的ip地址 function editHostFile() { #echo "edit the host file" #1./home/hadoop/host_ip.txt文件中讀取ip和hostname while read line do #提取文件中的ip ip=`echo $line | cut -d " " -f1` #提取文件中的用戶名 hostname=`echo $line | cut -d " " -f2` addIpToHostFile $ip $hostname done < /home/hadoop/automaticDeploy/host_ip.txt #讀取存儲ip的文件 #echo "edit the host file successfully" } editHostFile
以root用戶執行命令:
/home/hadoop/automaticDeploy/systems/addClusterIps.sh
2.4 關閉防火牆、SELINUX
closeFirewall.sh命令如下:
#! /bin/bash function closeFirewallAndGetenforce() { #1.關閉防火牆 firewallStatus=`firewall-cmd --state` if [[ $firewallStatus = "running" ]] then systemctl stop firewalld.service &&systemctl disable firewalld.service fi #2.關閉getenforce getenforceStatus=`getenforce` egrep "^SELINUX=enforcing" /etc/selinux/config >& /dev/null if [[ $getenforceStatus = "Enforcing" || $? -eq 0 ]] then sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config fi #3.重啟,使設置生效 #reboot } function startFirewallAndGetenforce() { #1.開啟防火牆 firewallStatus=`firewall-cmd --state` if [[ $firewallStatus != "running" ]] then systemctl enable firewalld.service && systemctl start firewalld.service fi #2.開啟getenforce getenforceStatus=`getenforce` egrep "^SELINUX=disabled" /etc/selinux/config >& /dev/null if [[ $getenforceStatus = "Disabled" || $? -eq 0 ]] then sed -i 's/^SELINUX=disabled/SELINUX=enforcing/' /etc/selinux/config fi #3.重啟,使設置生效 #reboot } operate=$1 if [ -z $operate ] then echo "參數為空,請輸入參數close或start" else if [[ $operate = "close" ]] then closeFirewallAndGetenforce fi if [[ $operate = "start" ]] then startFirewallAndGetenforce fi fi
這里提供開啟和關閉防火牆兩種功能,方便操作。以root用戶執行該shell命令時,需要輸入參數close或start:
/home/hadoop/automaticDeploy/systems/closeFirewall.sh close
2.5 添加系統bigdata用戶
autoCreateUser.sh代碼如下:
#! /bin/bash #創建bigdata用戶組,創建bigdata用戶並設置密碼 function createUserAndGroup() { echo "start to create user 'bigdata'!" user=$1 group=$2 #create group if not exists #在/etc/group中查找用戶組是否存在,並把錯誤輸出輸到/dev/null中 egrep "^$group" /etc/group >& /dev/null # 判斷上一命令是否等於0,不等於則創建用戶組 if [ $? -ne 0 ] then groupadd $group fi #create user if not exists egrep "^$user" /etc/passwd >& /dev/null if [ $? -ne 0 ] then useradd -g $group $user fi #在shell中使用expect實現自動輸入密碼,通常需要與'expect <<EOF EOF'、spawn、子expect一起使用 expect << EOF spawn passwd $user expect "New password:" send "${user}\r" expect "Retype new password:" send "${user}\r" expect eof; EOF } #刪除bigdata用戶,刪除bigdata用戶組 function deleteUserAndGroup() { user=$1 group=$2 echo "delete the user:" $user " and the userGroup:" $group userdel -r $user if [ $user != $group ] then groupdel $group fi } operate=$1 if [ -z $operate ] then echo "參數為空,請輸入參數create或delete" else if [[ $operate = "create" ]] then createUserAndGroup bigdata bigdata fi if [[ $operate = "delete" ]] then deleteUserAndGroup bigdata bigdata fi fi
這里提供創建、刪除用戶兩種操作,以root用戶執行該命令需要輸入參數create或者delete:
/home/hadoop/automaticDeploy/systems/autoCreateUser.sh create
2.6 配置yum源
由於大數據平台一般是在內網環境下搭建的,所以需要配置本地yum源,用以解決一些依賴包缺少的問題,這里以node1節點作為本地yum源所在的服務器,以CentOS-7.0-x86_64-bin-DVD1.iso作為yum源的source。
configureYum.sh代碼如下:
#! /bin/bash #配置yum源 function configureYumSource() { yumUrl=$1 yumFile=$2 #1.把CentOS-Media.repo文件非#開頭的行注釋掉 sed -i 's/^[^#]/#&/' $yumFile #2.配置本地源 echo "[base]" >> $yumFile echo "name=CentOS-Local" >> $yumFile echo "baseurl=$yumUrl" >> $yumFile echo "gpgcheck=0" >> $yumFile echo "enabled=1" >> $yumFile echo "gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7" >> $yumFile #3.清除YUM緩存 yum clean all > /dev/null 2>&1 #4.列出可用的YUM源 yum repolist > /dev/null 2>&1 } #處理並保證只有一個CentOS-Media.repo文件存在 function doWithRepoFile() { #1.進入到yum.repos.d目錄 cd /etc/yum.repos.d/ #2.查找/etc/yum.repos.d/目錄下是否存在.repo結尾的文件,存在則重命名為.repo.bak結尾的 fileResult=`find /etc/yum.repos.d/ -name "*.repo"` for file in $fileResult do onlyFile=`find /etc/yum.repos.d -wholename $file.bak` if [[ -z $onlyFile ]] then mv $file $file.bak fi done #3.只創建一個.repo文件用於配置本地yum源 result=`find /etc/yum.repos.d/ -name CentOS-Media.repo.bak` if [[ -z $result ]] then touch CentOS-Media.repo else cp CentOS-Media.repo.bak CentOS-Media.repo fi } ############################################################################# #同一函數及其調用的子函數,父函數與子函數均有一樣的變量名,而內容不一樣會報錯 ############################################################################# #配置本地源 function localYumSource() { systemUrl=$1 ip=$2 yumFile=/etc/yum.repos.d/CentOS-Media.repo #1.不存在則創建mount的目錄 if [ ! -d /var/iso ] then mkdir /var/iso fi #掛載系統,已掛載則不再次掛載 if [ ! -d /var/iso/CentOS_BuildTag ] then mount -o loop $systemUrl /var/iso fi #2.處理並保證只有一個CentOS-Media.repo的文件用於配置本地yum源 doWithRepoFile #3.配置yum源 configureYumSource file:///var/iso $yumFile #4.安裝相應的軟件 httpdIsExists=`rpm -qa | grep http` if [[ -z $httpdIsExists ]] then yum install -y httpd fi #5.開啟httpd使用瀏覽器訪問 #service httpd start httpdStatus=`systemctl status httpd.service` result=$(echo $httpdStatus | grep "Active: active (running)") if [[ $result = "" ]] then systemctl start httpd.service fi #6.將YUM源配置到httpd中,其他的服務器可通過網絡訪問這個內網中的YUM源 httpUrl=/var/www/html/CentOS-7.0 if [ ! -e $httpUrl/lock ] then cp -r /var/iso $httpUrl echo "lock" >> $httpUrl/lock fi #7.取消先前掛載的鏡像 強制取消,哈哈哈哈 umount -fl /var/iso #8.修改yum源指向的地址 sed -i 's/^baseurl\=file:\/\/\/var\/iso/baseurl\=http:\/\/'$ip'\/CentOS-7.0/' $yumFile #9.清除YUM緩存 yum clean all > /dev/null 2>&1 #10.列出可用的YUM源 yum repolist > /dev/null 2>&1 #echo "create the local yum source successfully" } #配置遠程yum源 function remoteYumSource() { ip=$1 yumUrl=http://$ip/CentOS-7.0 yumFile=/etc/yum.repos.d/CentOS-Media.repo #1.處理並保證只有一個CentOS-Media.repo的文件用於配置yum源 doWithRepoFile #2.配置yum源 configureYumSource $yumUrl $yumFile } hostname=$1 if [[ $hostname = "node1" ]] then localYumSource /opt/system/CentOS-7-x86_64-DVD-1804.iso 192.168.187.201 else remoteYumSource 192.168.187.201 fi
以root用戶執行代碼如下,參數$hostname一般為node1、node2、node3:
/home/hadoop/automaticDeploy/systems/configureYum.sh $hostname
2.7 配置SSH無密碼登錄
sshFreeLogin代碼如下:
#! /bin/bash function sshFreeLogin() { #1.檢測expect服務是否存在,不存在則使用yum安裝expect expectIsExists=`rpm -qa | grep expect` if [ -z $expectIsExists ] then yum -y install expect fi #2.密鑰對不存在則創建密鑰 [ ! -f /root/.ssh/id_rsa.pub ] && ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa while read line;do #提取文件中的ip hostname=`echo $line | cut -d " " -f2` #提取文件中的用戶名 user_name=`echo $line | cut -d " " -f3` #提取文件中的密碼 pass_word=`echo $line | cut -d " " -f4` expect <<EOF #復制公鑰到目標主機 spawn ssh-copy-id $hostname expect { #expect實現自動輸入密碼 "yes/no" { send "yes\n";exp_continue } "password" { send "$pass_word\n";exp_continue } eof } EOF # 讀取存儲ip的文件 done < /home/hadoop/automaticDeploy/host_ip.txt } sshFreeLogin
以root用戶執行代碼如下:
/home/hadoop/automaticDeploy/systems/sshFreeLogin.sh
2.8 配置JDK環境
configureJDK.sh代碼如下:
#! /bin/bash function configureJDK() { #1.在frames.txt中查看是否需要安裝java javaInfo=`egrep "^jdk" /home/hadoop/automaticDeploy/frames.txt` java=`echo $javaInfo | cut -d " " -f1` isInstall=`echo $javaInfo | cut -d " " -f2` #是否安裝 if [[ $isInstall = "true" ]];then #2.查看/opt/frames目錄下是否有java安裝包 javaIsExists=`find /opt/frames -name $java` if [[ ${#javaIsExists} -ne 0 ]];then if [ -d /usr/lib/java ];then rm -rf /usr/lib/java fi mkdir /usr/lib/java && chmod -R 777 /usr/lib/java #2.解壓到指定文件夾/usr/lib/java中 echo "開啟解壓jdk安裝包" tar -zxvf $javaIsExists -C /usr/lib/java >& /dev/null echo "jdk安裝包解壓完畢" java_home=`find /usr/lib/java -maxdepth 1 -name "jdk*"` #3.在/etc/profile配置JAVA_HOME profile=/etc/profile sed -i "/^export JAVA_HOME/d" $profile echo "export JAVA_HOME=$java_home" >> $profile #4.在/etc/profile配置PATH sed -i "/^export PATH=\$PATH:\$JAVA_HOME\/bin/d" $profile echo "export PATH=\$PATH:\$JAVA_HOME/bin" >> $profile sed -i "/^export CLASSPATH=.:\$JAVA_HOME/d" $profile echo "export CLASSPATH=.:\$JAVA_HOME/lib/dt.jar:\$JAVA_HOME/lib/tools.jar" >> $profile #5.更新/etc/profile文件 source /etc/profile && source /etc/profile else echo "/opt/frames目錄下沒有jdk安裝包" fi else echo "/opt/frames目錄下沒有jdk安裝包" fi } configureJDK
以root用戶執行代碼如下:
/home/hadoop/automaticDeploy/systems/configureJDK.sh
2.9 配置Scala環境
configureScala.sh代碼如下:
#! /bin/bash function configureScala() { #1.在frames.txt中查看是否需要安裝scala scalaInfo=`egrep "^scala" /home/hadoop/automaticDeploy/frames.txt` scala=`echo $scalaInfo | cut -d " " -f1` isInstall=`echo $scalaInfo | cut -d " " -f2` #是否安裝 if [[ $isInstall = "true" ]];then #1.查找/opt/frames目錄下是否有Scala安裝包 scalaIsExists=`find /opt/frames -name $scala` if [[ ${#scalaIsExists} -ne 0 ]];then if [ -d /usr/lib/scala ];then rm -rf /usr/lib/scala fi mkdir /usr/lib/scala && chmod -R 777 /usr/lib/scala #2.解壓到指定文件夾/usr/lib/scala中 echo "開始解壓scala安裝包" tar -zxvf $scalaIsExists -C /usr/lib/scala >& /dev/null echo "scala安裝包解壓完畢" scala_home=`find /usr/lib/scala -maxdepth 1 -name "scala-*"` #3.在/etc/profile配置SCALA_HOME profile=/etc/profile sed -i "/^export SCALA_HOME/d" $profile echo "export SCALA_HOME=$scala_home" >> $profile #4.在/etc/profile配置PATH sed -i "/^export PATH=\$PATH:\$SCALA_HOME\/bin/d" $profile echo "export PATH=\$PATH:\$SCALA_HOME/bin" >> $profile #5.更新/etc/profile文件 source /etc/profile && source /etc/profile else echo "/opt/frames目錄下沒有scala安裝包1" fi else echo "/opt/frames目錄下沒有scala安裝包2" fi } configureScala
以root用戶執行代碼如下:
/home/hadoop/automaticDeploy/systems/configureScala.sh
3.0 集群模塊整合自動化部署安裝
3.1 單機上整合第2點的9個模塊自動化批量執行
batchOperate.sh代碼如下:
#! /bin/bash hostname=$1 #1.ip地址修改,目前只能每台機器獨自修改ip地址 echo "1.ip地址修改暫無" #2.修改機器名hostname echo "2.修改hostname為node1" /home/hadoop/automaticDeploy/systems/changeHostname.sh $hostname #3.host配置文件修改 echo "3.把集群ip及其映射的hostname添加到/etc/hosts中" /home/hadoop/automaticDeploy/systems/addClusterIps.sh #4.關閉防火牆、SELINUX ,需要輸入參數close或start echo "4.關閉防火牆、SELINUX" /home/hadoop/automaticDeploy/systems/closeFirewall.sh close #5.添加bigdata用戶名 ,需要輸入參數create或delete echo "5.添加bigdata用戶名" /home/hadoop/automaticDeploy/systems/autoCreateUser.sh create #6.配置yum源 echo "6.配置yum源" /home/hadoop/automaticDeploy/systems/configureYum.sh $hostname #7.配置SSH無密碼登錄 echo "7.集群各節點之間配置SSH無密碼登錄" /home/hadoop/automaticDeploy/systems/sshFreeLogin.sh #8.配置JDK環境 echo "8.配置jdk環境" /home/hadoop/automaticDeploy/systems/configureJDK.sh #9.配置SCALA環境 echo "9.配置scala環境" /home/hadoop/automaticDeploy/systems/configureScala.sh echo ""
以root用戶執行代碼如下,參數$hostname一般為node1、node2、node3::
/home/hadoop/automaticDeploy/systems/batchOperate.sh $hostname
在一台機器上執行以上命令,可以迅速設置該台機器的系統環境。但是如果集群機器過多,則需要每台機器都要執行batchOperate.sh,所以需要3.2點在集群上一次性部署整個集群上機器的系統環境,而不需要每台機器都重復部署。
3.2 集群上自動化部署安裝
這里以node1為基點,集群上的所有操作觸發點都在node1上,操作原理為:在clusterOperate.sh代碼里,node1上本地執行batchOperate.sh設置本地機器的系統環境,而利用ssh遠程執行batchOperate.sh設置遠程機器的系統環境。
clusterOperate.sh代碼如下:
#! /bin/bash function clusterOperate() { #1.遠程復制文件 while read line; do hostname=`echo $line | cut -d " " -f2` echo "目前正在設置$hostname節點的系統環境" #默認node1為本地主機 if [[ $hostname = "node1" ]] then #2.本地主機操作 /home/hadoop/automaticDeploy/systems/batchOperate.sh $hostname else #3.遠程主機操作 if ssh -n $hostname test -e /home/hadoop/automaticDeploy then #3.1 存在則先刪除舊的 ssh -n $hostname "rm -rf /home/hadoop/automaticDeploy" fi #3.2 把本地的automaticDeploy里面的腳本文件復制到遠程主機上 scp -r /home/hadoop/automaticDeploy/ $hostname:/home/hadoop/automaticDeploy #3.3 把本地的/opt/frames里的軟件安裝包復制到遠程主機的/opt/frames上 #判斷遠程主機上/opt/frames是否存在,不存在則創建 if ssh -n $hostname test -e /opt/frames/;then echo "存在" > /dev/null else ssh -n $hostname "mkdir /opt/frames" fi #遍歷需要安裝的軟件 while read lineString; do software=`echo $lineString | cut -d " " -f1` isInstall=`echo $lineString | cut -d " " -f2` if [[ $isInstall = "true" ]];then if ssh -n $hostname test -e /opt/frames/$software;then echo "存在" > /dev/null else scp /opt/frames/$software $hostname:/opt/frames/$software fi fi done < /home/hadoop/automaticDeploy/frames.txt #4.遠程執行文件 ssh -n $hostname /home/hadoop/automaticDeploy/systems/batchOperate.sh $hostname fi done < /home/hadoop/automaticDeploy/host_ip.txt } clusterOperate
在node1節點上,以root用戶執行clusterOperate.sh,一次性部署集群三個節點的系統環境:
/home/hadoop/automaticDeploy/systems/clusterOperate.sh
到此,集群中每台機器的環境自動化設置完成,下一篇介紹如何自動化部署大數據組件hadoop、spark、hbase、hive、kafka等等。
所有shell文件代碼存放在github上,代碼可能寫得不是很完美,歡迎指出錯誤。
github地址為:https://github.com/SwordfallYeung/BigData_AutomaticDeploy
參考資料:
https://zhidao.baidu.com/question/502381951517702724.html
https://blog.csdn.net/qq_34685846/article/details/72825587
https://www.cnblogs.com/cute/archive/2011/08/26/2154137.html
https://www.cnblogs.com/mark-zhou/p/5976222.html
https://blog.csdn.net/kinger0/article/details/52251847
https://blog.csdn.net/wyl9527/article/details/72831567
https://blog.csdn.net/hello_hwc/article/details/40118129
http://www.codebelief.com/article/2017/02/26-examples-of-find-command-on-linux/
http://hadesmo.com/2015/07/20/sed.html