目錄:
前言
在linux管理中,shell腳本很是重要,它可以幫助我們完成很多繁瑣的工作,專注於更重要的事情上來,腳本的學習也是我們學習linux中所要遇到的比較困難的部分,因爲它需要對vim,正則,邏輯,程序化語言有一定的熟悉,shell編程是過程式,解釋執行的。它包括各種系統指令的組合,數據存儲(變量,數組)、表達式、語句。
在shell腳本中,包含一些命令或聲明,並符合一定格式的文本文件,在首行是shebang機制,如:
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
腳本在開頭查找執行本腳本的程序,此程序就在第一行命令。Shell腳本經常用於自動化常用命令,執行系統管理和故障排除,創建簡單的應用程序,處理文本或文件。
如何創建一個腳本
第一步,使用文本編輯器(vim)創建一個文件,一般都是以.sh結尾,在第一行必須包括shell聲明#!(即shebang機制)我們一般使用#!/bin/bash
[root@CT71 bin]# vim test.sh
1 #!/bin/bash 2 ~ 3 ~ 4 ~ 5 ~ 6 ~ 7 ~ 8 ~ 9 ~ 10 ~ 11 ~ 12 13 -- INSERT -- 1,12 All
第二步,添加註釋,shell腳本中的註釋都是以#開頭,後面跟上註釋內容(一般註釋寫什麼,我們一會兒就會說到)
1 #!/bin/bash 2 #Filename: test.sh 3 #Revision: 1.0 4 #Date: 2017-8-2 5 #Author: hahaha 6 #Description: ################ ~ ~ ~
第三步,編寫腳本內容,腳本內容可以寫我們常用的一些命令,比如查找我們磁盤中使用量最大的百分比等
1 #!/bin/bash 2 #Filename: disk.sh 3 #Revision: 1.0 4 #Date: 2017-8-2 5 #Author: hahaha 6 #Dessciption: 7 8 df | grep "dev/sd" | tr -s " " % | cut -d"%" -f5 | sort -nr | head -1 ~ ~ ~ ~ ~
第四步,給予腳本執行權限,即chmod +x shellname.sh,最後我們就可以執行我們的腳本了
[root@CT71 bin]# ll | grep "test.sh" -rw-r--r--. 1 root root 0 Aug 3 16:06 test.sh [root@CT71 bin]# chmod +x test.sh [root@CT71 bin]# ll | grep "test.sh" -rwxr-xr-x. 1 root root 0 Aug 3 16:06 test.sh
接下來我們說說們可以在註釋裏寫啥東西。
1. 第一行一般爲調用使用的語言
2. 程序名,避免更改文件名爲無法找到正確的文件
3. 版本號
4. 更改後的時間
5. 作者相關信息
6.該程序的作用,及注意事項
7. 最後是各版本的更新簡要說明
比如說:
1 #!/bin/bash
2 # Filename: hello.sh
3 # Revision: 1.1
4 # Date: 2017/06/01
5 # Author: wang
6 # Description: This is the first script
腳本調試
我們咋運行腳本之前,可以對腳本進行調試,這樣可以保證我們的腳本出錯的機率更低,一般我們常用的有兩個參數:
檢測腳本中的語法錯誤
bash -n /path/to/some_script
調試執行
bash -x /path/to/some_script
[root@CT71 bin]# bash -x link.sh + netstat -tn + grep tcp + cut -d: -f6 + sort -nr + uniq -c + tr -s ' ' : 1 192.168.111.1
接下來我們開始與腳本內容相關的知識,基礎知識包括變量(變量的種類,變量的命令規則,本地變量,環境變量,位置變量),執行後的狀態及狀態碼,算數運算與賦值。
變量相關
在shell腳本中的變量是弱類型的變量,語言的運行時會隱式做數據類型轉換。無須指定類型,默認均爲字符型;參與運算會自動進行隱式類型轉換,變量無須事先定義可直接調用。
變量的命令規則
1. 不能使程序中的保留字:例如if, for
2. 只能使用數字、字母及下劃線,且不能以數字開頭
3. 見名知義
4. 統一命名規則:駝峯命名法
1 for:錯誤 2 23var:錯誤 3 ip_w:正確 4 var:正確 5 _min:正確 6 someIp:正確
bash中變量的種類
根據變量的生效範圍等標準:
本地變量:生效範圍爲當前shell進程;對當前shell之外的其它shell進程,包括當前shell的子shell進程均無效
環境變量:生效範圍爲當前shell進程及其子進程局部變量:生效範圍爲當前shell進程中某代碼片斷(通常指函數)
位置變量: $1, $2, ...來表示,用於讓腳本在腳本代碼中調用通過命令行傳遞給它的參數
特殊變量:
$?, $0, $*, $@, $#,$$
在這些變量中,本地變量僅對當前shell有效,對子shell是沒有效的。而環境變量對當前shell及其子shell都有效,我們可以用env查詢所有的環境變量,用set查詢本地變量和環境,我們有一點需要知道,在linux中變量聲明以後會一直存在,除非我們把他們給刪除掉,刪除變量我們可以用unset varname
[root@CT71 bin]# echo $A
string
[root@CT71 bin]# unset A
[root@CT71 bin]# echo $A
[root@CT71 bin]# set | grep "^A"
ABRT_DEBUG_LOG=/dev/null
刪除了A變量
本地變量
設置變量:
(1) 可以是直接字串; name=“root"
(2) 變量引用: name="$USER"
(3) 命令引用: name=`COMMAND` name=$(COMMAND)
引用變量:
${varname}
$varname
“$varname”
[root@CT71 bin]# myName=BUG [root@CT71 bin]# echo $myName BUG [root@CT71 bin]# echo "$myName" BUG [root@CT71 bin]# echo ${myName} BUG
"":弱引用,其中的變量引用會被替換爲變量值
'':強引用,其中的變量引用不會被替換爲變量值,而保持原字符串
[root@CT71 bin]# echo "$USER" root [root@CT71 bin]# echo '$USER' $USER
轉譯:
\ 完全轉譯
""部分轉譯 \ ` ! $(""無法轉譯的字符)
'' 完全轉譯
轉譯的原因是因爲有些字符在linux下有特殊含義,但是,我們又需要用到它普通意義,所以我們需要對他們轉譯成非特殊字符供我們使用。
[root@CT71 app]# echo "$20.0"
0.0
[root@CT71 app]# echo "\$20.0"
$20.0
[root@CT71 app]# echo '$20.0'
$20.0
[root@CT71 app]# echo "!ll" echo "ll" ll [root@CT71 app]# echo '!ll' !ll
環境變量
環境變量的聲明:
export name=value
declare -x name=value
環境變量的引用:
$name
${name}
在前面我們已經說過如何查看我們的變量,但是,查看環境變量的命令還有幾個,如:env,printenv,export,declare –x,在bash中還有一些內建的環境變量:
PATH:命令查找的路徑
SHELL:我們使用的shell
USER:當前用戶名
UID:當前用戶UID
HOME:家目錄
PWD:當前工作目錄
SHLVL:當前所在的幾級shell
LANG:使用的字符集
MAIL:郵箱路徑
HOSTNAME:主機名
HISTSIZE:歷史命令記錄長度
_:上次執行的命令
[root@CT71 app]# env XDG_SESSION_ID=612 HOSTNAME=CT71 -----------------------------------------------------------------------主機名 SELINUX_ROLE_REQUESTED= TERM=xterm SHELL=/bin/bash ---------------------------------------------------------------------使用的shell HISTSIZE=1000 -----------------------------------------------------------------------歷史命令記錄長度 SSH_CLIENT=192.168.111.1 52880 22 SELINUX_USE_CURRENT_RANGE= SSH_TTY=/dev/pts/2 USER=root ---------------------------------------------------------------------------當前用戶名 LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00 ... ... MAIL=/var/spool/mail/root --------------------------------------------------------------郵箱路徑 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin --------------------命令查找路徑 PWD=/app ----------------------------------------------------------------------------當前的工作目錄 LANG=en_US.UTF-8 --------------------------------------------------------------------使用的字符集 ... ...
SHLVL=1 -----------------------------------------------------------------------------當前所在的幾級shell
HOME=/root --------------------------------------------------------------------------當前用戶家目錄
LOGNAME=root
SSH_CONNECTION=192.168.111.1 52880 192.168.111.110 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
OLDPWD=/root/bin
_=/usr/bin/env ----------------------------------------------------------------------上次執行的命令
只讀和位置變量
我們可以在linux中設置只讀變量,它的特點是隻能聲明,但不能修改和刪除
聲明只讀變量:
readonly name
declare –r name
查看只讀變量:
readonly –p
[root@CT71 app]# readonly H=2134 [root@CT71 app]# H=werq -bash: H: readonly variable [root@CT71 app]# readonly -p declare -r BASHOPTS="checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath" declare -ir BASHPID declare -r BASH_COMPLETION_COMPAT_DIR="/etc/bash_completion.d" declare -ar BASH_REMATCH='()' declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")' declare -ir EUID="0" declare -r H="2134" declare -ir PPID="57929" declare -r S declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor" declare -ir UID="0"
[root@CT71 app]# unset -f S 刪除只讀變量 [root@CT71 app]# echo $S [root@CT71 app]#
declare是一個shell的內建命令,用來顯示所有變量屬性和和值的,它還有一些常用的參數,比如上面的declare –r是用來設置只讀變量的,declare –f不僅顯示變量,還顯示函數,還有declare –x設置環境變量等
位置變量
位置變量其實就是在腳本代碼中調用通過命令行傳遞給腳本的參數。我們可以通過外在的參數傳遞給腳本以實現與腳本的交互操作,增強腳本功能。
在腳本中的$1,$2,$3…分別對應着腳本外面的第1個,第2個,第3個參數,$0代表的是命令本身,$*是傳遞給腳本的所有參數,全部參數合爲一個字符串
$@是傳遞給腳本的所有參數,每個參數爲獨立字符串,$#是傳遞給腳本的參數的個數($@ $* 只在被雙引號包起來的時候纔會有差異)
set -- 清空所有位置變量
1 #!/bin/bash 2 3 echo "$1" ~ ~ ------------------------------------------- [root@CT71 app]# chmod +x test.sh [root@CT71 app]# ll total 4 -rwxr-xr-x. 1 root root 23 Aug 3 19:22 test.sh [root@CT71 app]# ./test.sh Hello Hello
1 #!/bin/bash 2 echo "filename :$(basename $0)" ~ ~ ~ -----------------------------------------
[root@CT71 app]# ./test2.sh
filename :test2.sh
1 #!/bin/bash #tt1.sh 2 ./tt2.sh "$@" ~ ~ 1 #!/bin/bash #tt2.sh 2 3 echo "$@" ~ [root@CT71 app]# ./tt1.sh 1 2 3 4 5 1 2 3 4 5 --------------------------------------------------------------------- 1 #!/bin/bash #tt1.sh 2 ./tt2.sh "$#" ~ ~ 1 #!/bin/bash #tt2.sh 2 3 echo "$#" ~ [root@CT71 app]# ./tt1.sh 1 2 3 4 5 1
由於我不是在PATH所在的路徑下執行的腳本所以直接執行腳本是找不到的,必須要跟上確定的路徑./tt2.sh就是在本目錄下執行tt2.sh腳本
查詢變量
本地變量的查詢
set (即查本地,也查環境)
[root@CT71 app]# set | grep -C 4 "^PWD" PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"' PS1='[\u@\h \W]\$ ' PS2='> ' PS4='+ ' PWD=/app SELINUX_LEVEL_REQUESTED= SELINUX_ROLE_REQUESTED= SELINUX_USE_CURRENT_RANGE= SHELL=/bin/bash
環境變量的查詢
env
printenv
export
declare -x
[root@CT71 app]# printenv XDG_SESSION_ID=612 HOSTNAME=CT71 SELINUX_ROLE_REQUESTED= TERM=xterm SHELL=/bin/bash HISTSIZE=1000 SSH_CLIENT=192.168.111.1 52880 22 SELINUX_USE_CURRENT_RANGE= ... ...
進程的退出狀態與狀態碼
我們在系統中沒執行一個命令都會開闢一個進程,配置一個PID,當程序運行結束後,即進程結束後,都會返回一個值給變量“?”,通過返回的值,我們就可以瞭解到這個進程執行的結果如何,在返回的中,0 代表執行成功,1-255代表着不同的失敗,$?變量保存着最近的命令執行後的狀態。
除了程序自動的賦值外,我們也可以手動自定義程序退出的狀態碼,特別是在我們寫腳本時,通過條件語句進行判斷時,自定義的退出碼就派上大用場。
自定義退出狀態碼:
exit[n] n={1..255}
注意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出狀態取決於exit命令後面的數字
注意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決於腳本中執行的最後一條命令的狀態碼
1 #!/bin/bash 2 3 echo "Myname is Tony!" 4 5 exit 1 6 7 echo "Show my name" ~ ~ -------------------------------------------------- [root@CT71 app]# chmod +x tt3.sh [root@CT71 app]# ./tt3.sh Myname is Tony!
在這我們多說一點東西,如何查看進程以及PID,這裏有幾個變量和命令,我們來看一下:
變量$$:查看當前的PID
PPID:查看父進程的PID
SHLVL:顯示當前的shell是幾級shell
pstree:顯示進程樹
-p:同時顯示進程的PID
ps –ef :顯示進程信息
[root@CT71 app]# echo $$ 57933 [root@CT71 app]# echo $PPID 57929 [root@CT71 app]# pstree -p | grep -C 2 "bash" | `-{rsyslogd}(2281) |-smartd(577) |-sshd(1401)---sshd(57929)---bash(57933)-+-grep(61485) | `-pstree(61484) |-systemd-journal(367) [root@CT71 app]# echo $SHLVL 1 [root@CT71 app]# ps -ef | grep "bash" root 607 1 0 Jul31 ? 00:00:14 /bin/bash /usr/sbin/ksmtuned root 57933 57929 0 14:09 pts/2 00:00:01 -bash root 61495 57933 0 20:05 pts/2 00:00:00 grep --color=auto bash