<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      shell總結


      菜單

       

      生成菜單1:

      #!/bin/bash
      
      # 定義顏色變量
      RED='\033[1;31m'
      GREEN='\033[32m'
      YELLOW='\033[33m'
      BLUE='\033[34m'
      NORMAL='\033[0m'
      
      PS3=`echo -e "${GREEN}請選擇一個選項:${NORMAL}" `
      
      options=("選項1" "選項2" "選項3" "退出")
      select opt in "${options[@]}"
      do
          case "$opt" in
              "選項1")
                  echo -e "${YELLOW}你選擇了選項1${NORMAL}"
                  ;;
              "選項2")
                  echo -e "${YELLOW}你選擇了選項2${NORMAL}"
                  ;;
              "選項3")
                  echo -e "${YELLOW}你選擇了選項3${NORMAL}"
                  ;;
              "退出")
                  echo -e "${RED}退出程序${NORMAL}"
                  break
                  ;;
              *) echo -e "${RED}無效選項${NORMAL}";;
          esac
      done
      生成菜單法2:

      cat <<-EOF #cat h 顯示命令幫助 f 顯示磁盤分區 d 顯示磁盤掛載 m 查看內存使用 u 查看系統負載 q 退出程序 bag show rosbag EOF while true #死循環 do #選擇操作的內容 read -p "選擇內容(help h):" action #clear case $action in #case語句 h) cat <<-EOF #conmod h 顯示命令幫助 f 顯示磁盤分區 d 顯示磁盤掛載 m 查看內存使用 u 查看系統負載 q 退出程序 bag show rosbag EOF ;; f) fdisk -l ;; d) df -h ;; m) free -m ;; u) uptime ;; q) exit ;; bag) ssh -p 17042 cti@frp.ctirobot.com "ls -lh .ros/cti_all_bag" ;; esac done

       

      #!/usr/bin/env
      #創建用戶
      USER=$1
      ROOT_PASSWD="Fpc11100885"
      INIT_PASSWD="fPc11100885"
      #免密
      echo "" |ssh-keygen -t rsa -P ""
      while read host
      do
              sshpass -p "$ROOT_PASSWD" ssh -n -o StrictHostKeyChecking=no  -l root $host  "userdel -r $USER;useradd $USER;echo "$INIT_PASSWD"|passwd --stdin $USER"
              sshpass -p "$INIT_PASSWD" ssh-copy-id $USER@$host
      done<$2

       

      日志輸出: 

      要想將腳本中所有的標準輸出1和標準錯誤輸出2都自動寫到log中,可以在腳本開頭加上

      exec &>>./a.log 或者exec 1>>a.log 2>&1

       


      shell組命令與子進程

      • 1.組命令
      • 2.子進程
        • 2.1 什么是子進程
        • 2.2 創建子進程
        • 2.3 子進程總結
      • 3.如何檢測子shell與子進程
      • 4.當前shell運行

      1.組命令

      組命令,就是將多個命令劃分為一組,或者看成一個整體。

      用法
      區別

      Shell 組命令的寫法有兩種:

      { command1; command2;. . .;  }
      (command1; command2;. . . )

      1. 由花括號{}包圍起來的組命名在當前 Shell 進程中執行,而由小括號()包圍起來的組命令會創建一個子 Shell,所有命令都在子 Shell 中執行。
      2. 使用花括號{}時,花括號與命令之間必須要有一個空格,并且最后一個命令必須用一個分號或一個換行符結束
      3. 組命令可以將多條命令的輸出結果合并在一起,在使用重定向和管道時會特別方便。

      兩種寫法的重要不同:{}包圍的組命令在當前 Shell 進程中執行,由()包圍的組命令會創建一個子Shell,所有命令都會在這個子 Shell 中執行
      在子 Shell 中執行意味著,運行環境被復制給了一個新的 shell 進程,當這個子 Shell 退出時,新的進程也會被銷毀,環境副本也會消失,

      所以在子 Shell 環境中的任何更改都會消失(包括給變量賦值)。因此,在大多數情況下,除非腳本要求一個子 Shell,

      否則使用{}比使用()更受歡迎,并且{}的進行速度更快,占用的內存更少

      舉栗 
      將多條命令的輸出重定向到out.txt文件

      1.普通模式

      1. ls -l > out.txt #>表示覆蓋
      2. echo "test432" >> out.txt #>>表示追加
      3. cat test.txt >> out.txt

      2.使用組命令

      { ls -l ;echo "test432";cat test.txt; }>out.txt

      (ls -l ;echo "test432";cat test.txt)>out.txt

      組命令與管道結合

      (ls -l ;echo "test432";cat ../test.txt)|wc -l

      { { } } 和( ( ))組命令區別


      echo "test" | { { { echo "$SHLVL $BASH_SUBSHELL"; } } }  
      echo "$SHLVL" "$BASH_SUBSHELL"

      4 1
      4 0

      多個{}嵌套,{和{要有空格,且多層嵌套也只產生1層子shell


      ( ( ( echo $SHLVL $BASH_SUBSHELL) ) )
      echo $SHLVL $BASH_SUBSHELL

      4 3
      4 0

      多個()嵌套,(和(要有空格,且多層嵌套對產生多層子shell

      2.子進程

      2.1 什么是子進程

       

      子進程的概念是由父進程的概念引申而來的。在 Linux 系統中,系統運行的應用程序幾乎都是從 init(pid為 1 的進程)進程派生而來的,所有這些應用程序都可以視為 init 進程的子進程,而 init 則為它們的父進程。

       

      Shell 腳本是從上至下、從左至右依次執行的,即執行完一個命令之后再執行下一個。如果在 Shell 腳本中遇到子腳本(即腳本嵌套,但是必須以新進程的方式運行)或者外部命令,就會向系統內核申請創建一個新的進程,以便在該進程中執行子腳本或者外部命令,這個新的進程就是子進程。子進程執行完畢后才能回到父進程,才能繼續執行父腳本中后續的命令及語句。

       

      使用pstree -p命令就可以看到 init 及系統中其他進程的進程樹信息(包括 pid):

       

      systemd(1)─┬─ModemManager(796)─┬─{ModemManager}(821)
                  │                     └─{ModemManager}(882)
                  ├─NetworkManager(975)─┬─{NetworkManager}(1061)
                  │                       └─{NetworkManager}(1077)
                  ├─abrt-watch-log(774)
                  ├─abrt-watch-log(776)
                  ├─abrtd(773)
                  ├─accounts-daemon(806)─┬─{accounts-daemon}(839)
                  │                        └─{accounts-daemon}(883)
                  ├─alsactl(768)
                  ├─at-spi-bus-laun(1954)─┬─dbus-daemon(1958)───{dbus-daemon}(1960)
                  │                         ├─{at-spi-bus-laun}(1955)
                  │                         ├─{at-spi-bus-laun}(1957)
                  │                         └─{at-spi-bus-laun}(1959)
                  ├─at-spi2-registr(1962)───{at-spi2-registr}(1965)
                  ├─atd(842)
                  ├─auditd(739)─┬─audispd(753)─┬─sedispatch(757)
                  │               │                └─{audispd}(759)
                  │               └─{auditd}(752)

       

      2.2 創建子進程

      創建子進程的方式
      說明
       
      • 第一種只使用 fork() 函數,子進程和父進程幾乎是一模一樣的,父進程中的函數、變量(全局變量、局部變量)、文件描述符、別名等在子進程中仍然有效。我們將這種子進程稱為子 Shell(sub shell)

       

      1. 使用 fork() 函數創建一個子進程相當于對父進程進行了克隆,除了 PID(進程ID)等極少的參數不同外,子進程的一切都來自父進程,包括代碼、數據、堆棧、打開的文件等,就連代碼的執行位置(狀態)都是一樣的。
      2. 但是,后期隨著各自的發展軌跡不同,兩者會變得不一樣,但是在 fork() 出來的那一刻,兩者都是一樣的。
      組命令、命令替換、管道
      • 第二種使用 fork() 和 exec() 函數,即使用 fork()創建子進程后立即調用 exec() 函數加載新的可執行文件,而不使用從父進程繼承來的一切,子進程和父進程之間除了硬生生地維持一種“父子關系”外,再也沒有任何聯系了,它們就是兩個完全不同的程序。

      舉栗:
      在 ~/bin 目錄下有兩個可執行文件分別叫 a.out 和 b.out。現在運行 a.out,就會產生一個進程,比如叫做 A。在進程 A 中我又調用 fork() 函數創建了一個進程 B,那么 B 就是 A 的子進程,此時它們是一模一樣的。但是,我調用 fork() 后立即又調用 exec() 去加載 b.out,這可就壞事了,B 進程中的一切(包括代碼、數據、堆棧等)都會被銷毀,然后再根據 b.out 重建建立一切。這樣一折騰,B 進程除了 ID 沒有變,其它的都變了,再也沒有屬于 A 的東西了。

      1.以新進程的方式運行腳本文件,比如bash ./test.sh; chmod +x ./test.sh; ./test.sh

      2.在當前 Shell 中使用 bash 命令啟動新的 Shell

      2.3 子進程總結

      子 Shell 雖然能使用父 Shell 的的一切,但是如果子 Shell 對數據做了修改,比如修改了全局變量,這種修改也只能停留在子 Shell,無法傳遞給父 Shell。不管是子進程還是子 Shell,都是“傳子不傳父”。

      子 Shell 才是真正繼承了父進程的一切,這才像“一個模子刻出來的”;普通子進程和父進程是完全不同的兩個程序,只是維持著父子關系而已。

      3.如何檢測子shell與子進程

      echo $$輸出當前進程ID (當前shell的pid,也就是腳本運行的當前進程號),echo $PPID輸出父shell ID

       

      命令

      結果

      結論

      輸出當前進程與父進程ID

      echo $$;echo $PPID

      34451

      34450

       

      子進程形式輸出進程ID

      子進程

      bash

      echo $$;echo $PPID

      exit

      52886

      34451

      在普通的子進程中,$ 被展開為子進程的 ID

      組命令形式輸出進程ID

      子shell

      (echo $$;echo $PPID)

       

      34451

      34450

      子shell和父shell中的ID是一樣的

      這是因為$ 變量在子 Shell 中無效!Base 官方文檔說,在普通的子進程中,$ 確實被展開為子進程的 ID;

      但是在子 Shell 中,$ 卻被展開成父進程的 ID

      管道形式輸出進程ID

      子shell

      echo "test" | { echo $$;echo $PPID; }

      34451

      34450

      進程替換形式輸出進程ID

      read < <(echo $$ $PPID)

      $ echo $REPLY

      34451 34450


      除了 $,Bash 還提供了另外兩個環境變量——SHLVL 和 BASH_SUBSHELL,用它們來檢測子 Shell 非常方便。

      SHLVL 是記錄多個 Bash 進程實例嵌套深度的累加器,每次進入一層普通的子進程,SHLVL 的值就加 1。而 BASH_SUBSHELL 是記錄一個 Bash 進程實例中多個子 Shell(sub shell)嵌套深度的累加器,每次進入一層子 Shell,BASH_SUBSHELL 的值就加 1。

       
       
       命令結果知識點
      輸出變量

      echo "$SHLVL $BASH_SUBSHELL"

      1  0

       

      子進程形式輸出變量

      子進程

      創建一個腳本文件,命名為 test.sh,內容如下:

      #!/bin/bash echo "$SHLVL $BASH_SUBSHELL"

      *****************************************

      bash

      echo "$SHLVL $BASH_SUBSHELL"#2 0

      bash ./test.sh #3 0

      echo "$SHLVL $BASH_SUBSHELL"#2 0

      chmod +x ./test.sh;./test.sh #3 0

      echo "$SHLVL $BASH_SUBSHELL"#2 0

      exit #退出內層Shell

      echo "$SHLVL $BASH_SUBSHELL"#1 0

       

      bash ./test.sh./test.sh

      這兩種運行腳本的方式,在腳本運行期間會開啟一個子進程,

      運行結束后立即退出子進程

      產生新進程時,SHLVL的值加1

      組命令形式輸出變量

      子shell

      (echo "$SHLVL  $BASH_SUBSHELL")

      1  1 組命令、管道、命令替換這幾種方式都會產生子 Shell

      管道形式輸出變量

      子shell

      echo "test" | { echo "$SHLVL  $BASH_SUBSHELL"; }

      1  1

      命令替換形式輸出變量

      子shell

      var=$(echo "$SHLVL  $BASH_SUBSHELL")

      echo $var

      1 1

      四層組命令形式輸出變量

      子shell

      ( ( ( (echo "$SHLVL $BASH_SUBSHELL") ) ) )

      1 4

      進程替換形式輸出變量

       

      read < <(echo "$SHLVL  $BASH_SUBSHELL")

      echo $REPLY

       

      echo "hello" > >(echo "$SHLVL $BASH_SUBSHELL")

       

      1 0

      1 0

      進程替換只是借助文件在()內部和外部命令之間傳遞數據,

      并沒有創建子shell,()內部和外部的命令是在一個進程

      (也就是當前進程)中執行的

       

       

      4 當前shell運行,是內置命令

      調用所有普通的程序(包括另一個shell程序、其他sh腳本)都是子進程。
      只有在命令中寫明(),$(),``(反引號) 都是用來執行命令替換的,它們會在子 shell 中執行。比如echo $(ls),這里先用$()產生一個子shell,在調用ls時,又在這個子shell內部產生了一個專門執行ls的子進程,這里存在嵌套

      內建命令就是包含在bash Shell工具包中的命令,是bash Shell的骨干部分,除此之外,保留字(reserved words)也是bash Shell的骨干部分,保留字對于bash Shell具有特殊的含義,用來構建Shell語法結構,forifthenwhileuntil等都是保留字,但是,保留字本身不是一個命令,而是命令結構的一部分。

      Bash Shell的內建命令和保留字:

      $(( )) $[] expr等  行算術運算時,不需要啟動新的 shell 進程,所有的計算都是在當前的 shell 環境

                      #保留字,邏輯非

      :                 #不做任何事,只做參數展開

      .                 #讀取文件,并在當前Shell中執行它

      alias           #設置命令或命令行的別名

      bg              #將作業置于后臺運行

      bind           #將關鍵字序列與readline函數或宏綁定

      break         #保留字,跳出forwhileuntilselect循環

      builtin        #調用命令的內建命令格式,而禁用同名的函數,或者同名的擴展命令

      case           #保留字,多重選擇

      cd              #切換當前工作目錄

      command  #找出內建和外部命令;尋找內建命令而非同名函數

      continue    #保留字,到達下一次forwhileuntilselect循環

      declare      #聲明變量,定義變量屬性

      dirs            #顯示當前存儲目錄的列表

      disown       #將作業從表中移除

      do              #保留字,forwhileuntilselect循環的一部分

      done          #保留字,forwhileuntilselect循環的一部分

      echo          #打印參數

      elif             #保留字,if結構的一部分

      else           #保留字,if結構的一部分

      enable       #開啟和關閉內建命令

      esac          #保留字,case的一部分

      eval           #將參數作為命令再處理一遍

      exec          #以特定程序取代Shell或為Shell改變I/O

      exit           #退出Shell

      export       #將變量聲明為環境變量

      fc              #與命令歷史一起運行

      fg              #將作業置于前臺運行

      fi               #保留字,if結構的一部分

      for             #保留字,for結構的一部分

      function    #定義一個函數

      getops      #處理命令行選項

      hash         #記錄并指定命令的路徑名

      help          #顯示內建命令的幫助信息

      history      #顯示歷史命令信息

      if               #保留字,if結構的一部分

      in              #保留字,case的一部分

      jobs          #顯示在后臺運行的作業

      kill            #向進程傳送信號

      let             #使變量執行算術運算

      local          #定義局部變量

      logout       #shell中注銷

      popd         #從目錄棧中彈出目錄

      pushd        #將目錄壓入目錄棧

      pwd           #顯示當前工作目錄

      read          #從標準輸入中讀入一行

      readonly   #將變量定義為只讀

      return       #從函數或腳本中返回

      select       #保留字,生成選擇菜單

      set            #設置Shell選項

      shift          #變換命令行參數

      suspend   #中止Shell的執行

      test           #評估條件表達式

      then          #保留字,if結構的一部分

      time #保留字,輸出統計出來的命令執行時間,其輸出格式由TIMEFORMAT變量來控制

      times        #針對Shell及其子Shell,顯示用戶和系統CPU的時間之和

      trap          #設置信號捕捉程序

      type          #確認命令的源

      typeset     #聲明變量,定義變量屬性,與declare等價

      ulimit        #設置和顯示進程占用資源的限制

      umask      #設置和顯示文件權限碼

      unalias      #取消別名定義

      unset        #取消變量或函數的定義

      until          #保留字,一種循環結構

      wait          #等待后臺作業完成

      while         #保留字,一種循環結構

       

      冒號是bash Shell中一個特殊的符號,可表示永真,相當于TRUE關鍵字。

      例:冒號表示永真的用法

      #!/bin/bash

      i=0

      while :        #冒號相當于TRUE

      do

              if ((i >= 3 ))

              then

                      break

              fi

              echo $((++i))

      done

      結果:1

                2

                3

       

      冒號可以清空一個文件。:>命令是常用的清空文件的命令

      命令:cat loggg

      結果:Positional Parameter is NULL

      命令::>loggg          #將冒號重定向到文件并將文件清空

                cat loggg

      結果:

       

      冒號最重要的用法是:不做任何事,只做參數展開。

       

      12.1.2、圓括號結構
      圓括號結構能夠強制將其中的命令運行在子Shell中,其基本格式為:
      (
      command1
      command2
      ...
      commandn
      )
      該結構表示圓括號內的n條命令在子Shell中運行,bash版本3之后定義的內部變量BASH_SUBSHELL記錄了子Shell的層次。

       

      例:圓括號結構用法和BASH_SUBSHELL變量
      #!/bin/bash
      echo "The level of father Shell is: $BASH_SUBSHELL" #打印父Shell的層次
      outervar=OUTER #定義一個變量
      ( #進入子Shell
      echo "The level of SubShell is: $BASH_SUBSHELL"
      innervar=INNER #在子Shell內定義一個變量
      echo "innervar=$innervar"
      echo "outervar=$outervar"
      )
      #回到父Shell
      echo "The level of father Shell is: $BASH_SUBSHELL"
      if [ -z "$innervar" ] #測試子Shell中定義的變量是否為空
      then
      echo "The \$innervar is not defined in main body."
      else
      echo "The \$innervar is defined in main body."
      fi
      結果:The level of father Shell is: 0 #父Shell的BASH_SUBSHELL值
      The level of SubShell is: 1 #子Shell的BASH_SUBSHELL值
      innervar=INNER
      outervar=OUTER #子Shell能使用父Shell定義的變量
      The level of father Shell is: 0
      #子Shell定義的變量innervar在父Shell中為空,說明子Shell中變量對父Shell是不可見的
      The $innervar is not defined in main body.

       

      BASH_SUBSHELL是從0開始計數的整數,它依次記錄子Shell的層次。

       

      例:測試子Shell定義環境變量是否對父Shell有效
      #!/bin/bash
      #在父Shell中定義變量outervar
      echo "-----------------IN MAINSHELL--------------------"
      outervar=OUTER
      echo "outervar=$outervar"
      ( #進入子Shell
      echo "-----------------IN SUBSHELL---------------------"
      innervar=INNER
      echo "innervar=$innervar"
      outervar=OUTER-INNER #更改父Shell所定義的outervar變量值
      echo "outervar=$outervar"
      #將innervar和outervar聲明為環境變量
      export innervar
      export outervar
      )
      #回到父Shell,測試innervar和outervar的值是否與子Shell中的定義一樣
      echo "-----------------RETURN TO MAINSHELL-------------"
      echo "innerver=$innervar"
      echo "outervar=$outervar"
      結果:-----------------IN MAINSHELL--------------------
      outervar=OUTER
      -----------------IN SUBSHELL---------------------
      #下面打印子Shell中innervar和outervar變量的值
      innervar=INNER
      outervar=OUTER-INNER
      -----------------RETURN TO MAINSHELL-------------
      innerver=
      outervar=OUTER
      #父shell中innervar為空,outervar仍為原來的值,這說明子Shell對兩個變量
      的定義和更改對父Shell不起作用

       

      子Shell只能繼承父Shell的一些屬性,但是,子Shell不可能反過來改變父Shell的屬性。
      子Shell能夠從父Shell繼承得來的屬性有:
      當前工作目錄
      環境變量
      標準輸入、標準輸出和標準錯誤輸出
      所有已打開的文件標識符
      忽略的信號
      子Shell不能從父Shell繼承得來的屬性有:
      除了環境變量和 .bashrc文件中定義變量之外的Shell變量
      未被忽略的信號處理
      因此,子Shell能夠設置獨立于父Shell的子環境。

       

      例:子Shell設定bash Shell選項的用法
      #!/bin/bash
      (
      set -C #開啟-C選項防止重定向時覆蓋文件
      :> outputnull #試圖用冒號清空outputnull文件
      )
      #在父Shell覆蓋一個文件,測試子Shell開啟的-C選項是否對父Shell生效
      cat subsenv.sh > outputnull
      執行:./subsenv.sh
      結果:./subsenv.sh:行4: outputnull: 無法覆蓋已存在的文件
      #提示執行腳本時出錯,不能覆蓋已存在的文件,這說明set -C在子Shell中已經起作用
      執行:cat outputnull
      #查看outputnull內容,為subsenv.sh腳本本身,這說明父Shell仍能覆蓋文件,set -C不起作用
      結果:#!/bin/bash
      (
      set -C
      :> outputnull
      )
      cat subsenv.sh > outputnull

       

      例:利用子Shell測試變量是否定義過
      #!/bin/bash
      if (set -u; : $var)
      then
      echo "Variable is set."
      fi
      執行:var=2012
      export var #將var聲明為環境變量
      結果:Variable is set. #該腳本能測試出var已經定義
      set -u命令用于設置Shell選項,u選項是nounset的意思,表示當使用未定義的變量時,輸出錯誤信息,并強制退出。

       

      子Shell還可以接收到父Shell從管道傳送來的數據。

       

      例:打印/etc/passwd文件中與root關鍵字所匹配的行
      執行:cat /etc/passwd | (grep 'root')
      結果:root:x:0:0:root:/root:/bin/bash
      operator:x:11:0:operator:/root:/sbin/nologin

       

      子Shell可以將一個計算量較大的任務分成若干個小任務并行執行。

       

      例:子Shell用于并行計算的用法
      #!/bin/bash
      #用圓括號結構創建三個子Shell同時執行,每個子Shell都是搜索某個目錄下與root關鍵字匹配的行,排序后輸出到某文件
      (grep -r "root" /etc/* | sort > part1) &
      (grep -r "root" /usr/local/* | sort > part2) &
      (grep -r "root" /lib/* | sort > part3) &
      wait #等待后臺執行的作業全部完成后,再執行下面的命令
      #將part1、part2和part3三個臨時文件合并,排序后重定向到parttotal文件
      cat part1 part2 part3 | sort > parttotal
      echo "Run time of this script is: $SECONDS" #輸出該腳本的執行時間
      結果:Run time of this script is: 22 #腳本運行了22秒
      執行:wc -l parttotal #對結果文件的行計數
      結果:1492 parttotal

       

      grep的-r選項表示遞歸搜索。每個圓括號結構之外都有一個&符號,這表示將此命令放在后臺執行,繼續執行下一條命令,如果去掉&符號,腳本需要將(grep -r "root" /etc/* | sort > part1)命令執行完畢后才能執行下一條命令。wait
      命令是一個內建命令,用于等待后臺執行的作業全部完成后再執行下面的命令。假如沒有這條命令,腳本將三個子Shell放到后臺執行后,將直接執行合并臨時文件的命令,此時,三個子Shell可能并未執行完畢。因此,臨時文件中的結果是不完整的,合并后也將產生不完整的最終結果。

       

      子Shell是允許嵌套調用的,可在函數或圓括號結構內再次調用圓括號結構創建子Shell。

       

      12.2、Shell的限制模式
      Shell的限制模式簡稱RSH(Restricted Shell),處于限制模式的Shell下運行一個腳本或腳本片段,將會禁用一些命令或操作。Shell的限制模式是Linux系統基于安全方面的考慮,目的是為了限制腳本用戶的權限,并盡可能地減小腳本所帶來的危害。
      Shell的限制模式限制的命令和操作有:
      用cd命令更改當前工作目錄的命令。
      更改重要環境變量的值,包括$PATH、$SHELL、$BASH_ENV、$ENV和$SHELLOPTS
      輸出重定向符號,包括>、>>、>|、>&、<>和&>符號。
      調用含有一個或多個斜杠(/)的命令名稱。
      使用內建命令exec。
      使用set +r等命令關閉限制模式。

       

      例:Shell的正常模式和限制模式的區別
      #!/bin/bash
      #在正常模式下改變當前工作目錄
      echo "Changing current work directory"
      cd /etc
      echo "Now in $PWD"
      set -r #利用Shell選項使下面的代碼運行在限制模式下,r是restricted的簡寫
      echo
      echo "------------IN RESTRICTED MODE-------------"
      #驗證在限制模式下能否改變當前工作目錄
      echo "Trying to change current work directory"
      cd /usr/local
      echo "Now in `pwd`"
      echo
      #驗證在限制模式下能否改變$SHELL變量的值
      echo "Trying to change \$SHELL"
      SHELL="/bin/sh"
      echo "\$SHELL=$SHELL"
      echo
      #驗證在限制模式下能否執行重定向操作
      echo "Trying to redirect output to a file"
      who > outputnull
      ls -l outputnull
      結果:Changing current work directory
      Now in /etc #Shell在正常模式下改變當前工作目錄

       

      ------------IN RESTRICTED MODE-------------
      #開始在限制模式下運行
      Trying to change current work directory
      ./resshell.sh: 第 9 行:cd: 受限的 #cd命令出錯,被限制了
      Now in /etc #當前工作目錄沒有改變

       

      Trying to change $SHELL
      ./resshell.sh:行13: SHELL: 只讀變量 #SHELL變量在限制模式下是只讀的
      $SHELL=/bin/bash

       

      Trying to redirect output to a file
      ./resshell.sh:行17: outputnull: 受限的: 無法重定向輸出 #redirect操作出錯

       

      ls: 無法訪問outputnull: 沒有那個文件或目錄 #outputnull沒有被創建

       

      還有一種以限制模式運行腳本的方式,就是將Sha-bang符號(#!)后的語句改成/bin/bash -r,-r表示在限制模式下運行該腳本。

       

      例:以/bin/bash -r方式進入限制模式
      #!/bin/bash -r
      #驗證在限制模式下能否讀取$SHELLOPTS變量的值
      echo "\$SHELLOPTS=$SHELLOPTS"
      echo
      echo "Changing current work directory"
      cd /etc
      echo "Now in $PWD"
      echo
      echo "Trying to change \$SHELL"
      SHELL="/bin/sh"
      echo "\$SHELL=$SHELL"
      echo
      echo "Trying to redirect output to a file"
      who > outputnull
      ls -l outputnull
      結果:$SHELLOPTS=braceexpand:hashall:interactive-comments
      #能夠讀取$SHELLOPTS的值
      Changing current work directory
      ./anotherres.sh: 第 5 行:cd: 受限的
      Now in /home/xiaomiao/test

       

      Trying to change $SHELL
      ./anotherres.sh:行9: SHELL: 只讀變量
      $SHELL=/bin/bash

       

      Trying to redirect output to a file
      ./anotherres.sh:行13: outputnull: 受限的: 無法重定向輸出
      -rw-rw-r-- 1 xiaomiao xiaomiao 65 8月 14 11:49 outputnull

       

      12.3、進程處理
      fork是Linux系統的一種系統調用(system calls),系統調用用于請求內核服務,這也是進程訪問硬件的唯一方法。fork是創建新進程的系統調用,fork創建的子進程是父進程的副本,兩個進程具有同樣的環境、打開的文件、用戶標志符、當前工作目錄和信號等。
      UNIX是第一個允許每個系統用戶控制多個進程的操作系統,這種機制稱為用戶控制的多任務(user-controlled multitasking),Linux操作系統延續了此特性。

       

      12.3.1、進程和作業
      進程和作業是有區別的:一個正在執行的進程稱為作業,一個作業可以包含多個進程。因此,作業是用戶層面的概念,而進程是操作系統層面的概念。
      進程是一個具有一定獨立功能的程序關于某個數據集合的一次運行活動,進程在運行中不斷地改變其運行狀態。
      通常,一個運行進程必須具有以下三種基本狀態:就緒(Ready)狀態、運行(Running)狀態和阻塞(Blocked)狀態。

       

      引起進程阻塞的事件可有多種,例如,等待I/O完成、申請緩沖區不能滿足、等待信號等。
      一個進程在運行期間,不斷地從一種狀態轉換到另一種狀態,它可以多次處于就緒狀態和執行狀態,也可以多次處于阻塞狀態。
      Linux系統為每個進程分配一個數字以標識這個進程,這個數字就是進程號。同時,創建該進程的Shell為此進程創建一個數字,也用于標識這個進程,這個數字稱為作業號。
      作業號屬于Shell,進程號屬于Linux。
      作業號標識的是在此Shell下運行的所有進程。

       

      后臺運行一個作業,方括號中的[1]是作業號,方括號后面的6355是進程號
      執行:grep -r "root" /etc/* | sort > part1 &
      結果:[1] 6355
      執行:grep -r "root" /usr/local/* | sort > part2 &
      結果:[2] 6409
      [1] 完成 grep --color=auto -r "root" /etc/* | sort > part1
      #提示[1]號作業已經完成

       

      默認情況下,當我們輸入下一條命令時,Shell才提示后臺運行的作業已經結束,而實際上,該作業可能已經早就運行結束。如果需要當后臺運行的作業一結束,Shell就顯示信息,就需要開啟norify選項,簡寫為b。

       

      norify選項的功能
      執行:set -b #開啟norify選項
      grep -r "root" /etc/* | sort > part1 &
      結果:[1] 6545
      結果:[1]+ 完成 grep --color=auto -r "root" /etc/* | sort > part1

       

      12.3.2、作業控制
      進程是針對整個Linux系統而言的,作業是針對Shell而言的。
      作業有兩種運行方式:前臺運行和后臺運行。前臺運行的作業指作業能夠控制當前終端或窗口,且能接收用戶的輸入;而后臺運行的作業則不在當前激活的終端或窗口中運行,是在用戶“看不見”的情況下運行。內建命令fg可將后臺運行的作業放到前臺,而&符號使得作業在后臺運行。

       

      Sleep10.sh腳本,休眠10秒后結束
      #!/bin/bash
      sleep 10
      執行:./sleep10.sh &
      結果:[1] 6707
      執行:fg #將[1]號作業放到前臺運行
      結果:./sleep10.sh
      #Shell等待[1]號作業運行完畢,才顯示下一行提示符

       

      只有一個作業在后臺運行,fg命令不帶任何參數就能將該作業放到前臺運行。當有多個作業在后臺運行時,不帶任何參數的fg命令將最近提交的那個后臺作業放置到前臺。fg命令如果要在多個后臺作業中挑選符合條件的作業,可使用作業號、作業的命令字符等參數。

       

      fg命令利用作業號指定作業
      執行:./sleep20.sh & #提交第1個后臺作業
      結果:[1] 6819
      執行:./sleep10.sh & #提交第2個后臺作業
      結果:[2] 6821
      執行:fg %1 #將[1]號作業放到前臺運行
      結果:./sleep20.sh #[1]號作業是sleep20.sh腳本
      [2] 完成 ./sleep10.sh
      #在等待[1]號作業的過程中,[2]號作業運行完畢

       

      指定作業方法及其意義:
      %n #n為后臺作業的作業號
      %string #命令以string字符串開始的后臺作業
      %?string #命令包含string字符串的后臺作業
      %+或%% #最近提交的后臺作業
      %- #最近第二個提交的后臺作業

       

      jobs命令用于顯示所有的后臺作業。

       

      jobs命令的用法:
      執行:./sleep20.sh &
      結果:[1] 6992
      執行:./sleep20.sh &
      結果:[2] 6994
      執行:./sleep10.sh &
      結果:[3] 6996
      執行:jobs #顯示所有后臺運行的作業
      結果:[1] 運行中 ./sleep20.sh &
      [2]- 運行中 ./sleep20.sh &
      [3]+ 運行中 ./sleep10.sh &
      執行:jobs -l #帶上-l參數,顯示作業的進程號
      結果:[1] 6992 運行中 ./sleep20.sh &
      [2]- 6994 運行中 ./sleep20.sh &
      [3]+ 6996 運行中 ./sleep10.sh &

       

      在作業運行時按下“Ctrl+Z”組合鍵即可將正在運行的作業阻塞。

       

      將正在運行的作業阻塞的用法:
      執行:vim sleep10.sh #用vim打開文件
      #!/bin/bash
      sleep 10

      #按下“Ctrl+Z”組合鍵,出現如下信息,說明vim sleep10.sh作業進入阻塞狀態
      [1]+ 已停止 vim sleep10.sh
      執行:jobs
      結果:[1]+ 已停止 vim sleep10.sh
      執行:fg #fg命令使vim sleep10.sh作業重新轉到前臺

       

      在“Ctrl+Z”組合鍵之后輸入bg命令可使阻塞狀態的作業轉入后臺運行。

       

      執行:./sleep20.sh
      ^Z #Ctrl+Z組合鍵
      結果:[1]+ 已停止 ./sleep20.sh
      執行:bg
      結果:[1]+ ./sleep20.sh &
      執行:jobs
      結果:[1]+ 運行中 ./sleep20.sh &
      [1]+ 完成 ./sleep20.sh

       

      注意,fg、bg和jobs命令只能以作業號為參數來指定作業,這三個命令是不能使用進程號的。而kill、disown和wait命令既能以作業號指定作業,也可以用進程號指定作業。

       

      disown命令用于從Shell的作業表中刪除作業,作業表就是由jobs命令所列出的作業列表,disown可以指定刪除作業表中的作業。

       

      disown命令的用法:
      執行:vi input &
      結果:[1] 2856
      執行:vi loggg &
      結果:[2] 2857

       

      [1]+ 已停止 vim input
      執行:jobs
      結果:[1]- 已停止 vim input
      [2]+ 已停止 vim loggg
      執行:disown %- #刪除最近第2個提交的作業
      結果:bash: 警告:刪除進程組 2856 中已停止的任務 1
      #Shell提示已經刪除進程號為2856的作業,即最近第2個提交的vi input作業
      執行:disown 2857 #以進程號的方式指定所要刪除的作業
      結果:bash: 警告:刪除進程組 2857 中已停止的任務 2
      #Shell提示已經刪除進程號為2857的作業
      執行:jobs #作業列表已經為空
      結果:

       

      wait命令用于等待后臺作業完成。

       

      例:wait命令的用法
      #!/bin/bash
      ls /etc | grep "rc[0-9]" &
      echo "The Scirpt quits now!"
      wait
      執行:./backls.sh #將wait命令注釋掉后的運行結果
      結果:The Scirpt quits now! #打印完這行語句后,腳本就已經結束
      rc0.d #但是后臺的ls作業仍然在運行
      rc1.d
      rc2.d
      rc3.d
      rc4.d
      rc5.d
      rc6.d
      #輸入Enter鍵退出
      執行:./backls.sh #wait命令存在時的運行結果
      結果:The Scirpt quits now!
      rc0.d
      rc1.d
      rc2.d
      rc3.d
      rc4.d
      rc5.d
      rc6.d #腳本等待后臺的ls作業運行結束后才結束

       

      12.3.3、信號
      信號是在軟件層次上對中斷機制的一種模擬,在原理上,一個進程收到一個信號與處理器收到一個中斷請求可以說是一樣的。信號是異步的,一個進程不必通過任何操作來等待信號的到達,事實上,進程也不知道信號到底什么時候到達。信號事件的發生有兩個來源:硬件來源和軟件來源。信號是進程間通信機制中唯一的異步通信機制,可以看做是異步通知,通知接收信號的進程有哪些事情發生了。信號機制經過POSIX實時擴展后,除了基本通知功能外,還可以傳遞附加信息。

       

      向進程發送信號大多通過“Ctrl”鍵加上一些功能鍵來實現的。
      Ctrl組合鍵、信號類型及其意義:
      Ctrl+C INT信號,即interrupt信號 停止當前運行的作業
      Ctrl+Z TSTP信號,即terminal stop信號 使當前運行的作業暫時停止(進入阻塞狀
      態)
      Ctrl+\ QUIT信號 Ctrl+C的強化版本,當Ctrl+C無法停止
      作業時,使用此組合鍵
      Ctrl+Y TSTP信號,即terminal stop信號 當進程從終端讀取輸入數據時,暫時停止
      該進程

       

      “Ctrl+Z”組合鍵實際上與“Ctrl+Y”是類似的,都是向進程發送TSTP信號,表示將進程暫時停止,但是它們的區別在于:“Ctrl+Y”組合鍵僅可以在進程從終端讀取輸入數據時,暫時停止該程序,而“Ctrl+Z”組合鍵則可以隨時暫時停止進程。

       

      除了利用組合鍵發送信號之外,內建命令kill可用于向進程發送TERM(即terminal)信號,功能與INT信號類似,也用于停止進程。而kill命令可以通過進程號、作業號或進程命令名向任何作業發送信號。

       

      kill命令的用法:
      執行:./sleep20.sh &
      結果:[1] 6101
      執行:kill %1 #通過作業號殺死進程
      jobs
      結果:[1]+ 已終止 ./sleep20.sh

       

      例:kill命令通過用進程號殺掉自己的進程的用法
      #!/bin/bash
      kill $$ #位置參數$$表示本身的進程號
      echo "Does this line appear?"
      結果:已終止 #一運行腳本就終止了
      執行:echo $?
      結果:143
      退出碼143大于128表示腳本是被系統強行結束的,然而,該腳本的退出碼還有其他含義的:當Shell腳本收到信號時,退出碼是128+N,N是該腳本所收到信號的標號,此時,腳本收到的是TERM信號,TERM信號的標號正好是15。
      Kill -l命令還可以列出kill命令能發出的所有信號及其標號。

       

      12.3.4、trap命令
      trap是Linux的內建命令,它用于捕捉信號,trap命令可以指定收到某種信號時所執行的命令。trap命令的格式為:trap command sig1 sig2 ... sigN
      該格式表示當trap命令收到sig1 sig2 ... sigN中任意一個信號時,執行command命令,command命令完成后,腳本繼續收到信號前的操作,直到腳本執行結束。

       

      例:trap命令捕捉INT信號的用法
      #!/bin/bash
      #一旦收到INT信號,執行雙引號內的echo命令
      trap "echo 'You hit CONTROL+C!'" INT
      while :; do #使用冒號表示永真,無限循環
      let count=count+1 #記錄進入循環的次數
      echo "This is the $count sleep"
      sleep 5 #每次循環休眠5秒
      done
      結果:This is the 1 sleep
      This is the 2 sleep
      ^CYou hit CONTROL+C! #第1次輸入“Ctrl+C”
      This is the 3 sleep #第2次休眠停止,立即進入第3次休眠
      This is the 4 sleep
      ^CYou hit CONTROL+C! #第2次輸入“Ctrl+C”
      This is the 5 sleep #第4次休眠停止,立即進入第5次休眠
      This is the 6 sleep
      ^Z #輸入“Ctrl+Z”結束腳本
      [1]+ 已停止 ./traploop.sh

       

      trap命令還可以忽略某些信息,即進程收到某些信息后不做任何處理。只要將trap命令的command用空字符串代替即可(””或'')。

       

      例:trap命令忽略信號的用法
      #!/bin/bash
      trap "" TERM INT #忽略對TERM和INT 兩種信號的處理,如果還要忽略其他信
      號,將它們添加到INT之后
      while :; do
      sleep 5
      done
      結果:./nokillme.sh &
      [3] 6470
      執行:kill %3 #試圖殺死nokillme.sh進程
      jobs #nokillme.sh仍然運行
      結果:[3] 運行中 ./nokillme.sh &
      執行:kill -9 %3 #用更為強勁的命令殺死nokillme.sh進程
      jobs #nokillme.sh已殺死
      結果:[3] 已殺死 ./nokillme.sh
      由于kill %3命令發送的是TERM信號,腳本的trap命令忽略了對TERM信號的處理。因此,kill %3命令不能殺死nokillme.sh進程。而kill -9 %3命令kill向3號作業發送9號信號殺死進程,9號信號實際上就是KILL信號,因此,kill -9 %3命令等價于kill -KILL %3命令。

       

      子Shell能繼承父Shell所忽略的信號,但是,不能繼承父Shell未忽略的信號。
      forever.sh腳本:
      #!/bin/bash
      while :; do
      sleep 5
      done
      subsig.sh腳本:
      #!/bin/bash
      trap "" QUIT #忽略QUIT信號
      trap "echo 'You want to kill me'" TERM #捕捉到TERM信號后,打印提示信息
      #TERM捕捉,但沒有忽略
      ( #將forever.sh腳本作為子Shell,子Shell將無限休眠
      ./forever.sh
      )
      執行:./subsig.sh &
      結果:[3] 6679 #返回父Shell的作業號和進程號
      執行:kill -3 6679 #向父Shell發送3號信號,即QUIT信號
      執行:ps -a
      結果: PID TTY TIME CMD
      6679 pts/0 00:00:00 subsig.sh #父Shell未退出,說明QUIT信號被忽略
      6680 pts/0 00:00:00 forever.sh
      6685 pts/0 00:00:00 sleep
      6686 pts/0 00:00:00 ps
      執行:kill -3 6680 #向子Shell發送3號信號,即QUIT信號
      ps -a
      結果: PID TTY TIME CMD
      6679 pts/0 00:00:00 subsig.sh
      6680 pts/0 00:00:00 forever.sh#子Shell也未退出,說明QUIT信號被忽略
      6701 pts/0 00:00:00 sleep
      6702 pts/0 00:00:00 ps
      執行:kill 6679 #向父Shell發送TERM信號
      ps -a
      結果: PID TTY TIME CMD
      6679 pts/0 00:00:00 subsig.sh #父Shell仍未被殺掉
      6680 pts/0 00:00:00 forever.sh
      6713 pts/0 00:00:00 sleep
      6714 pts/0 00:00:00 ps
      執行:kill 6680 #向子Shell發送TERM信號
      結果:已終止 #子Shell立刻被終止
      You want to kill me #并打印出父Shell對TERM信號的響應信息

       

      [3] 退出 143 ./subsig.sh #父shell隨著子Shell的終止而終止

       

       


      跳板機:

      [fpc@localhost script]# cat jumpserver.sh 
      #!/bin/bash
      trap '' INT
      echo -e "\e[1;31m-----------------------------------------------------"
      cat <<-EOF
                     1)optical modem                        
                     2)master DNS                          
                     3)slave DNS                             
                     4)router                             
                  5)virtual host1                      
                     6)virtual host2                     
      EOF
      echo -e "-----------------------------------------------------\e[0m"
      while :
      do
      echo -ne "\e[1;32mplease input one number: (1,2,3,4,5): \e[0m"
          read -p "" num
          case $num in 
              1)
                  ssh fpc@192.168.6.3 
                  ;;
              2)
                  ssh fpc@192.168.6.66
                  ;;
              3)
                  exit
                  ;;
              4)
                  ssh fpc@10.10.10.254
                  ;;
              5)
                  ssh fpc@10.10.10.11
                  ;;
              6)
                  ssh fpc@10.10.10.12
                  ;;
              *)
                  echo "input error,input again"
          esac
      done

      分發公鑰:

      注意:

      1. 并發執行{}& ,不常用,parallel 命令來并發執行命令可以提高效率。首先,您需要確保安裝了 parallel 工具
      2. shell中調用expect,EOF中必須是tab鍵
      3. 并發控制:文件句柄中增加$thead行
      #!/bin/bash
      thread=10
      tmp_fifofile=/tmp/$$.fifo
      mkfifo $tmp_fifofile
      exec 8<> $tmp_fifofile
      rm -f $tmp_fifofile
      for i in `seq $thread`
      do
              echo >&8
      done
      
      password="Fpc11100885"
      user="root"
      >distributed_hosts
      rpm -q expect &>/dev/null
      if [ $? -eq 0 ];then
              echo "install expect"
              sudo yum install -y expect
      fi
      if [ ! -f "~/.ssh/id_rsa" ];then
              ssh-keygen  -P ""  -f ~/.ssh/id_rsa
      fi
      for host in `cat ./network_hosts`
      do
              read -u 8
              {
              ping -c 1 -w 2 $host &>/dev/null
              if [ $? -eq 0 ];then
                      echo $host >> distributed_hosts
                      /usr/bin/expect <<-EOF
                      spawn ssh-copy-id ${user}@$host
                      expect {
                      "yes/no" {send "yes\r";exp_continue}
                      "password" {send "$password\r";exp_continue}
                      eof {send_tty "eof"}
                      }
                      EOF
      
              fi
              echo >&8
              }&
              wait
              echo "distribute finished"
      done

       

       

      # 并發執行
      for host in $hosts; do
          # 后臺執行命令
          sshpass -p "$ROOT_PASSWD" ssh -n -o StrictHostKeyChecking=no -l root$host "userdel -r $USER; useradd$USER; echo \"$INIT_PASSWD\" | passwd --stdin$USER" &
          sshpass -p "$INIT_PASSWD" ssh-copy-id$USER@$host &
          sshpass -p "$ROOT_PASSWD" ssh-copy-id root@$host &
      
          # 等待所有后臺命令完成
          wait
      
          # 執行其他操作
          # ...
      done
      
      每個 ssh 命令都被發送到后臺執行,wait 命令用于等待所有后臺命令完成。這種方法簡單且高效,是 Bash 中實現并發執行的常見方式。

       

       傳輸文件:

      [root@iZuf6eblqtavferh526stwZ ~]# vim transferFile.sh 
      
      exec 1>transfer.log 2>failed.log
      transfer(){
              echo "transfer: $SHLVL"
              srcFile=$1
              dstFile=$2
              if [ ! -e "$srcFile" ];then
                      echo "$srcFile文件不存在,檢查文件" >&2
                      exit 1
              fi
              cat hosts|while read host
              do
                      echo "*********tranfer to $host*********"
                      ssh -n -o   StrictHostKeyChecking=no fpc@$host  "if [ ! -e "$dstFile" ];then mkdir -p $dstFile;fi;"
                      scp  -r -o StrictHostKeyChecking=no $srcFile fpc@$host:$dstFile
                      if [ $? -eq 0 ];then
                              echo "transfer $srcFile to $host:$dstFile success" 
                      else
                              echo "transfer $srcFile to $host:$dstFile failed"
                      fi
              done
      }
      transfer $1 $2
      

        

      部署kafka,zookeeper:
      
      
      #!/usr/bin/env bash
      #創建用戶
      #exec >init_system.log 2>&1
      USER=$1
      ROOT_PASSWD="Fpc11100885"
      INIT_PASSWD="fPc11100885"
      SRC_DIR="/root/srcdata"
      DST_DIR="/opt/dstdata"
      JAVA_PACKAGE="jdk-8u211-linux-x64.tar.gz"
      ZOOKEEPER_PACKAGE="zookeeper-3.4.14.tar.gz"
      SCALA_PACKAGE="scala-2.13.0-M5.tgz"
      KAFKA_PACKAGE="kafka_2.13-3.0.0.tgz"
      REMOTE_INSTALL_DIR="/opt/install_dir"
      REMOTE_JAVA_DIR="/opt/java"
      REMOTE_ZOOKEEPER_DIR="/opt/zookeeper"
      REMOTE_SCALA_DIR="/opt/scala"
      REMOTE_KAFKA_DIR="/opt/kafka"
      
      #免密
      remote_hosts="
      192.168.1.10
      192.168.1.11
      192.168.1.12"
      
      remote_exec(){
              for host in $remote_hosts
              do
                      for cmd in "$@"
                      do
                                      #echo $#:$cmd
                              ssh -o StrictHostKeyChecking=no root@$host "$cmd" &
                      done
                      wait
                      echo "remote exec并發執行結束"
              done
      
      
      }
      
      
      remote_transfer(){
              for host  in $remote_hosts
              do
              echo "**********$host:remote tranfer file:************BASH_SUBSHELL:$BASH_SUBSHELL*****************SHLVL:$SHLVL*************************"
              ssh -n -o  StrictHostKeyChecking=no root@$host "if [ ! -e \"$DST_DIR\" ];then mkdir -p $\"$DST_DIR\";fi"
              if [ ! -e "$SRC_DIR"  -a  ! -e "$SRC_DIR/${JAVA_PACKAGE}" ];then
                      echo "檢查目錄或者文件是否存在"
                      exit 1
              fi
                      for file in "$@"
                      do
                              echo $#:$file
                              scp  -r     "$SRC_DIR"/"${file}" root@"${host}":"${DST_DIR}"  &
      
                      done
              wait
              echo "remote transfer并發執行結束"
              done
      }
      
      if [ -d /root/.ssh ];then rm -rf /root/.ssh;fi
      echo  "" |ssh-keygen -t rsa -P ""
      for host in $remote_hosts
      do
              sshpass -p "$ROOT_PASSWD" ssh -n -o StrictHostKeyChecking=no  -l root $host  "userdel -r $USER;useradd $USER;echo "$INIT_PASSWD"|passwd --stdin $USER"
              sshpass -p "$INIT_PASSWD" ssh-copy-id $USER@$host
              sshpass -p "$ROOT_PASSWD" ssh-copy-id root@$host
      
      done
      # 關閉防火墻和firellwalld
      #for host in $hosts
      #do
      #       ssh -o StrictHostKeyChecking=no root@$host "systemctl stop firewalld || systemctl disabled firewalld"
      #       ssh -o StrictHostKeyChecking=no root@$host "setenforce 0 ||  sed -ir \"s#SELINUXTYPE=targeted#SELINUXTYPE=disabled#g\" /etc/selinux/config"
      #done
      cmd1="systemctl stop firewalld || systemctl disabled firewalld"
      cmd2="setenforce 0 ||  sed -ir \"s#SELINUXTYPE=targeted#SELINUXTYPE=disabled#g\" /etc/selinux/config"
      commands=("$cmd1" "$cmd2")
      #remote_exec "${cmd1}" "${cmd2}"
      remote_exec "${commands[@]}"
      #安裝jdk
      remote_exec "yum remove   java-11-openjdk*  java-1.8.0-openjdk* -y"
      remote_exec "yum list installed | grep java &>/dev/null && echo  \"卸載jdk失敗\" || echo \"卸載jdk成功\" "
      remote_exec "if [ -e $REMOTE_INSTALL_DIR ];then rm -rf ${REMOTE_INSTALL_DIR};fi"
      remote_exec "mkdir -p ${REMOTE_INSTALL_DIR}"
      remote_exec "if [ -e $REMOTE_JAVA_DIR ];then rm -rf ${REMOTE_JAVA_DIR};fi"
      remote_exec "if [ -e $REMOTE_ZOOKEEPER_DIR ];then rm -rf ${REMOTE_ZOOKEEPER_DIR};fi"
      remote_transfer "${JAVA_PACKAGE}"
      remote_exec "tar xvf ${DST_DIR}/${JAVA_PACKAGE}  -C ${REMOTE_INSTALL_DIR}/"
      remote_exec "ln -sf ${REMOTE_INSTALL_DIR}/jdk1.8.0_211 ${REMOTE_JAVA_DIR}"
      cat >${SRC_DIR}/export_java_env.sh <<-EOF
      export JAVA_HOME=${REMOTE_JAVA_DIR}
      export PATH=\$PATH:\${JAVA_HOME}/bin:\${JAVA_HOME}/jre
      EOF
      remote_transfer "export_java_env.sh"
      remote_exec "mv ${DST_DIR}/export_java_env.sh /etc/profile.d/"
      remote_exec "source /etc/profile.d/export_java_env.sh"
      remote_exec "which java;java -version"
      #停止舊kafka和zookeeper進程,刪除zookeerp上的broker節點
      remote_exec "ps -ef|grep -v grep|grep kafka|awk '{print \$2}' > /tmp/kfz_pid"
      remote_exec 'if [ -s /tmp/kfz_pid ];then kill -9 `cat /tmp/kfz_pid`;rm -f /tmp/kfz_pid;fi'
      
      remote_exec "${REMOTE_ZOOKEEPER_DIR}/bin/zkCli.sh rmr /brokers/ids/"
      
      remote_exec "jps|grep QuorumPeerMain|grep -v grep|cut -d\" \" -f1 > /tmp/zoo.pid;cat /tmp/zoo.pid"
      remote_exec 'if [ -s /tmp/zoo.pid ];then kill -9 `cat /tmp/zoo.pid`;rm -f /tmp/zoo.pid;fi '
      
      #安裝zookeeper
      remote_transfer "${ZOOKEEPER_PACKAGE}"
      remote_exec "tar xvf ${DST_DIR}/${ZOOKEEPER_PACKAGE} -C ${REMOTE_INSTALL_DIR}/"
      remote_exec "ln -sf ${REMOTE_INSTALL_DIR}/zookeeper-3.4.14 ${REMOTE_ZOOKEEPER_DIR}"
      cat > ${SRC_DIR}/hosts <<-EOF
      192.168.1.10 zookeeper1
      192.168.1.11 zookeeper2
      192.168.1.12 zookeeper3
      EOF
      remote_transfer "hosts"
      remote_exec "\mv ${DST_DIR}/hosts /etc/hosts -f"
      #remote_exec "bash;hostname"
      remote_exec "\cp -f  ${REMOTE_ZOOKEEPER_DIR}/conf/{zoo_sample,zoo}.cfg"
      cat >${SRC_DIR}/zoo.tmp <<-EOF
      server.1=192.168.1.10:2888:3888
      server.2=192.168.1.11:2888:3888
      server.3=192.168.1.12:2888:3888
      EOF
      remote_transfer zoo.tmp
      remote_exec "cat ${DST_DIR}/zoo.tmp >> ${REMOTE_ZOOKEEPER_DIR}/conf/zoo.cfg"
      remote_exec "if [ ! -e /tmp/zookeeper ];then mkdir /tmp/zookeeper;fi"
      remote_exec 'if [ `hostname` == "zookeeper1" ];then echo 1 > /tmp/zookeeper/myid;fi'
      remote_exec 'if [ `hostname` == "zookeeper2" ];then echo 2 > /tmp/zookeeper/myid;fi'
      remote_exec 'if [ `hostname` == "zookeeper3" ];then echo 3 > /tmp/zookeeper/myid;fi'
      remote_exec "${REMOTE_ZOOKEEPER_DIR}/bin/zkServer.sh start"
      remote_exec "${REMOTE_ZOOKEEPER_DIR}/bin/zkServer.sh status"
      sleep 10
      #安裝scala
      remote_transfer "${SCALA_PACKAGE}"
      remote_exec "tar xvf ${DST_DIR}/${SCALA_PACKAGE} -C ${REMOTE_INSTALL_DIR}"
      remote_exec "ln -sf ${REMOTE_INSTALL_DIR}/scala-2.13.0-M5 ${REMOTE_SCALA_DIR}"
      cat > ${SRC_DIR}/export_scala_env.sh<<-EOF
      export SCALA_HOME=${REMOTE_SCALA_DIR}
      export PATH=\$PATH:\${SCALA_HOME}/bin
      EOF
      remote_transfer "export_scala_env.sh"
      remote_exec "mv ${DST_DIR}/export_scala_env.sh /etc/profile.d/"
      remote_exec "source /etc/profile.d/export_scala_env.sh"
      remote_exec "which scala;scala --version"
      #安裝kafka
      remote_exec "if [ -e /tmp/kafka-logs ];then rm -rf /tmp/kafka-logs;fi"
      remote_transfer "${KAFKA_PACKAGE}"
      remote_exec "tar xvf ${DST_DIR}/${KAFKA_PACKAGE} -C ${REMOTE_INSTALL_DIR}"
      remote_exec "ln -sf ${REMOTE_INSTALL_DIR}/kafka_2.13-3.0.0 ${REMOTE_KAFKA_DIR}"
      remote_exec 'if [ `hostname` == "zookeeper1" ];then sed -i  "s#broker.id=0#broker.id=1#g" '"$REMOTE_KAFKA_DIR/config/server.properties;"'fi'
      remote_exec 'if [ `hostname` == "zookeeper2" ];then sed -i  "s#broker.id=0#broker.id=2#g" '"$REMOTE_KAFKA_DIR/config/server.properties;"'fi'
      remote_exec 'if [ `hostname` == "zookeeper3" ];then sed -i  "s#broker.id=0#broker.id=3#g" '"$REMOTE_KAFKA_DIR/config/server.properties;"'fi'
      remote_exec 'sed -i "/^\#listeners=/a\listeners=PLAINTEXT:\/\/`hostname -i`:9092" '"$REMOTE_KAFKA_DIR"'/config/server.properties'
      remote_exec 'sed -i "s#localhost:2181#192.168.1.10:2181,192.168.1.11:2181,192.168.1.12:2181#g" '"$REMOTE_KAFKA_DIR"'/config/server.properties'
      remote_exec "${REMOTE_KAFKA_DIR}/bin/kafka-server-start.sh -daemon ${REMOTE_KAFKA_DIR}/config/server.properties"
      sleep 30
      #驗證kafka,分布式,只要在一臺執行即可
      remote_exec "if [ \`hostname\` == \"zookeeper1\" ];then ${REMOTE_KAFKA_DIR}/bin/kafka-topics.sh --bootstrap-server 192.168.1.10:9092,192.168.1.11:9092,192.168.1.12:9092 --list --topic fpc |grep -v '^\$' >/tmp/topicIsAlive;fi"
      remote_exec "if [ -s /tmp/topicIsAlive  -a  \`hostname\` == \"zookeeper1\" ];then ${REMOTE_KAFKA_DIR}/bin/kafka-topics.sh --bootstrap-server 192.168.1.10:9092,192.168.1.11:9092,192.168.1.12:9092 --delete --topic fpc;fi"
      remote_exec "if [ \`hostname\` == \"zookeeper1\" ];then ${REMOTE_KAFKA_DIR}/bin/kafka-topics.sh --bootstrap-server 192.168.1.10:9092,192.168.1.11:9092,192.168.1.12:9092 --create --topic fpc --partitions 3 --replication-factor 3;fi"
      remote_exec "${REMOTE_KAFKA_DIR}/bin/kafka-topics.sh --describe --bootstrap-server 192.168.1.10:9092,192.168.1.11:9092,192.168.1.12:9092 --topic fpc"

       

       

       

      集群一鍵啟停通用腳本:
      設計集群的一鍵啟停,檢測,所有主機要同時檢測

      1、進程起來很慢,花費30分鐘后進程起來后持續5分鐘掛掉(可能進程配置錯誤,進程所在服務器磁盤滿了等)
      2、進程起來很快,花費1分鐘起來持續10分鐘掛掉
      3、進程起來很快,然后一直持續正常
      4、進程起來很慢,然后一直持續正常

       

      [root@localhost ~]# cat kafka_tools.sh
      hosts="192.168.1.10 192.168.1.11 192.168.1.12"
      stop(){
      for host in $hosts
      do
      status $host
      if [ $? -ne 0 ];then
      echo "$host:Kafka is already stopped"
      continue
      else
      ssh -o StrictHostKeyChecking=no $host "/opt/kafka/bin/kafka-server-stop.sh"
      count=0
      while (( $count < 5 ))
      do
      status $host
      if [ $? -ne 0 ];then
      echo "$host:Kafka is stopped"
      break
      fi
      echo "$host:Kafka is stopping,..please wait..."
      sleep 3
      let count++
      done
      if [ $count -eq 5 ];then
      echo "進程停止失敗,請登錄$host排查"
      fi
      fi

      
      

      done
      }

      
      

      start(){
      for host in $hosts
      do
      status $host
      if [ $? -eq 0 ];then
      echo "$host:Kafka is already started"
      continue
      else
      ssh -o StrictHostKeyChecking=no $host "/opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.properties"
      count=0
      while (( $count < 5 ))
      do
      status $host
      if [ $? -eq 0 ];then
      echo "$host:Kafka is started"
      break
      fi
      echo "$host:Kafka is starting,..please wait..."
      sleep 3
      let count++

      #放在這里也可以

      #if [ $count -eq 5 ];then   
      #echo "進程停止失敗,請登錄$host排查"
      #fi
      done

      #放在這里也可以,因為都是上面if條件不滿足的時候才自增
      if [ $count -eq 5 ];then   
      echo "進程停止失敗,請登錄$host排查"
      fi

      done
      }

       

      #要循環5次檢測進程都是正常,進程才算啟動起來了
      status(){
      sts_count=0
      res_count=0
      while [ $sts_count -lt 5 ]
      do
      ssh -o StrictHostKeyChecking=no $1 "jps|grep -w Kafka"
      if [ $? -eq 0 ];then
      res_count=`expr $res_count + 1`
      fi
      sts_count=`expr $sts_count + 1`
      done

      
      

      if [ $res_count -eq 5 ];then
      return
      else
      return 100
      fi
      }

      
      

      case $1 in
      start)
      start
      ;;
      stop)
      stop
      ;;
      status)

      #這里設計目的:是因為想要在start,stop里面去調用status函數,同時又能直接sh $0 status檢查進程狀態,所以將for循環放在這里
      for host in $hosts
      do
      status $host
      if [ $? -eq 0 ];then
      echo "$host:Kafka is started"
      else
      echo "$host:Kafka is stopped"
      fi
      done
      ;;
      *)
      echo "USAGE: sh $0 (start,stop,status)"
      ;;
      esac

      
      

       

      ansible:
      http://www.rzrgm.cn/michael-xiang/p/10462749.html
      https://getansible.com/
      https://www.zsythink.net/archives/tag/ansible/page/6/
      http://www.rzrgm.cn/f-ck-need-u/p/7576137.html#ansible
      https://www.bilibili.com/video/av33611758/?from=search&seid=7420958755659258683
      https://ithelp.ithome.com.tw/users/20031776/ironman/1022
      https://ansible-tran.readthedocs.io/en/latest/index.html

      復雜示例#

      駿馬金龍 (junmajinlong.com)

      寫出好的 ansible-playbook 還是要多閱讀優秀的 playbook,這里先列出幾個可供學習的示例資源:

      • https://github.com/ansible/ansible-examples 一個面向初學者的 ansible playbook 收集倉庫
      • https://galaxy.ansible.com/ui/ 這里就有很多流行的應用示例了,進階看

      列出一個感覺比較清晰簡潔的例子#

      Copy
      .
      ├── LICENSE.md
      ├── README.md
      ├── group_vars
      │   └── all
      ├── hosts
      ├── images
      │   ├── check.png
      │   ├── nosql_primer.png
      │   ├── replica_set.png
      │   ├── scale.png
      │   ├── sharding.png
      │   └── site.png
      ├── playbooks
      │   └── testsharding.yml
      ├── roles
      │   ├── common
      │   │   ├── files
      │   │   │   ├── 10gen.repo.j2
      │   │   │   ├── RPM-GPG-KEY-EPEL-6
      │   │   │   └── epel.repo.j2
      │   │   ├── handlers
      │   │   │   └── main.yml
      │   │   ├── tasks
      │   │   │   └── main.yml
      │   │   └── templates
      │   │       ├── hosts.j2
      │   │       └── iptables.j2
      │   ├── mongoc
      │   │   ├── files
      │   │   │   └── secret
      │   │   ├── tasks
      │   │   │   └── main.yml
      │   │   └── templates
      │   │       ├── adduser.j2
      │   │       ├── mongoc.conf.j2
      │   │       └── mongoc.j2
      │   ├── mongod
      │   │   ├── files
      │   │   │   └── secret
      │   │   ├── tasks
      │   │   │   ├── main.yml
      │   │   │   └── shards.yml
      │   │   └── templates
      │   │       ├── mongod.conf.j2
      │   │       ├── mongod.j2
      │   │       ├── repset_init.j2
      │   │       └── shard_init.j2
      │   └── mongos
      │       ├── files
      │       │   └── secret
      │       ├── tasks
      │       │   └── main.yml
      │       └── templates
      │           ├── enablesharding.j2
      │           ├── mongos.conf.j2
      │           ├── mongos.j2
      │           └── testsharding.j2
      ├── site.yml
      └── tree.txt
      
      21 directories, 38 files
      

      site.yml 文件的內容如下:

      Copy
      ---
      # This Playbook would deploy the whole mongodb cluster with replication and sharding.
      
      - hosts: all
        roles:
        - role: common
      
      - hosts: mongo_servers
        roles:
        - role: mongod
      
      - hosts: mongoc_servers
        roles:
        - role: mongoc
      
      - hosts: mongos_servers
        roles:
        - role: mongos
      
      - hosts: mongo_servers
        tasks:
        - include: roles/mongod/tasks/shards.yml

       https://www.junmajinlong.com/ansible/index/

      posted @ 2024-10-19 09:49  _java_python  閱讀(48)  評論(0)    收藏  舉報
             [00:00.000] 作詞 : 陳信榮
          [00:01.000] 作曲 : 周傳雄
          [00:02.000] 編曲 : 周傳雄
          [00:03.000] 制作人 : 周傳雄
          [00:29.259]過完整個夏天
          [00:34.742]憂傷并沒有好一些
          [00:41.185]開車行駛在公路無際無邊
          [00:47.320]有離開自己的感覺
          [00:52.453]
          [00:53.347]唱不完一首歌
          [00:59.370]疲倦還剩下黑眼圈
          [01:05.596]感情的世界傷害在所難免
          [01:11.703]黃昏再美終要黑夜
          [01:18.292]依然記得從你口中說出再見堅決如鐵
          [01:24.732]昏暗中有種烈日灼身的錯覺
          [01:30.171]黃昏的地平線
          [01:33.230]劃出一句離別
          [01:36.313]愛情進入永夜
          [01:42.165]
          [01:42.881]依然記得從你眼中滑落的淚傷心欲絕
          [01:49.290]混亂中有種熱淚燒傷的錯覺
          [01:54.774]黃昏的地平線
          [01:57.816]割斷幸福喜悅
          [02:00.915]相愛已經幻滅
          [02:07.171]
          [02:19.647]唱不完一首歌
          [02:25.497]疲倦還剩下黑眼圈
          [02:31.753]感情的世界傷害在所難免
          [02:37.881]黃昏再美終要黑夜
          [02:42.994]
          [02:44.363]依然記得從你口中說出再見堅決如鐵
          [02:50.872]昏暗中有種烈日灼身的錯覺
          [02:56.291]黃昏的地平線
          [02:59.393]劃出一句離別
          [03:02.507]愛情進入永夜
          [03:08.340]
          [03:09.205]依然記得從你眼中滑落的淚傷心欲絕
          [03:15.531]混亂中有種熱淚燒傷的錯覺
          [03:20.937]黃昏的地平線
          [03:23.991]割斷幸福喜悅
          [03:27.025]相愛已經幻滅
          [03:34.375]
          [03:58.563]依然記得從你口中說出再見堅決如鐵
          [04:04.694]昏暗中有種烈日灼身的錯覺
          [04:10.141]黃昏的地平線
          [04:13.156]劃出一句離別
          [04:16.228]愛情進入永夜
          [04:21.297]
          [04:22.863]依然記得從你眼中滑落的淚傷心欲絕
          [04:29.401]混亂中有種熱淚燒傷的錯覺
          [04:34.714]黃昏的地平線
          [04:37.774]割斷幸福喜悅
          [04:40.913]相愛已經幻滅
          [05:39.200] 配唱制作人 : 吳佳明
          [05:39.533] 鋼琴 : 周傳雄
          [05:39.866] 吉他 : 許華強
          [05:40.199] 鼓 : Gary?Gideon
          [05:40.532] 貝斯 : Andy?Peterson
          [05:40.865] 弦樂編寫 : 吳慶隆
          [05:41.198] 弦樂 : 孔朝暉/顧文麗/隋晶晶/梁中樞/尹淑占/王言/關旗
          [05:41.531] 和聲編寫 : 周傳雄
          [05:41.864] 和聲 : 周傳雄
          [05:42.197] 錄音師 : 林世龍/沈文釧/Geoffrey Lee
          [05:42.530] 混音師 : 王晉溢
          [05:42.863] 錄音室 : 強力/HASAYAKE/Atomic?&?Audioplex?(Singapore)
          [05:43.196] 混音室 : 白金
          [05:43.529] OP : Sony/ATV?Music?Publishing?Taiwan/哈薩雅琪有限公司
          [05:43.862] SP : Sony/ATV?Music?Publishing?Taiwan?
      
          
           
          
           
      主站蜘蛛池模板: 一本色道久久综合亚洲精品| 免费人成网站免费看视频| 四虎库影成人在线播放| 国产超高清麻豆精品传媒麻豆精品 | 亚洲人成网线在线播放VA| 蜜桃传媒av免费观看麻豆| 国产人妻高清国产拍精品| 亚洲av乱码久久亚洲精品| 国产乱码精品一区二区三| 国产午夜精品理论大片| av新版天堂在线观看| 9色国产深夜内射| 国产av人人夜夜澡人人爽麻豆| 999福利激情视频| 美日韩精品综合一区二区| 国产片av在线观看国语| 97国产揄拍国产精品人妻| 色爱综合另类图片av| 日本视频高清一区二区三区| 国产美女久久久亚洲综合| 亚洲一区二区三区黄色片| 国产不卡免费一区二区| 国产精品综合av一区二区国产馆| 忘忧草在线社区www中国中文| 久久亚洲精品11p| 亚洲成人av综合一区| 国产果冻豆传媒麻婆精东 | 亚洲不卡一区三区三区四| 蜜臀av久久国产午夜福利软件| 欧美偷窥清纯综合图区| 国产精品成人午夜福利| 东北妇女精品bbwbbw| 在线高清免费不卡全码| 91老熟女老人国产老太| 久久成人国产精品免费软件| 国产在线一区二区不卡| 国产精品第二页在线播放| 67194熟妇在线观看线路| 国产精品久久毛片| 嫩草欧美曰韩国产大片| 麻豆成人精品国产免费|