Shell編程入門基礎上

前言

爲何學 Shell

Shell 腳本語言是實現 Linux/UNIX 系統管理及自動化運維所必備的重要工具, Linux/UNIX 系統的底層及基礎應用軟件的核心大都涉及 Shell 腳本的內容。每個合格 的Linux 系統管理員或運維工程師,都須要可以熟練地編寫 Shell 腳本語言,並可以閱讀系統及各種軟件附帶的 Shell 腳本內容。只有這樣才能提高運維人員的工做效率,適 應曰益複雜的工做環境,減小沒必要要的重複工做,從而爲我的的職場發展奠基較好的基礎php

什麼是 shell

Shell 是一個命令解釋器,它在操做系統的最外層,負責直接與用戶對話,把用戶的輸入解釋給操做系統,並處理各類各樣的操做系統的輸出結果,輸出屏幕返回給用戶。
html

這種對話方式能夠是:前端

  • 交互的方式:從鍵盤輸入命令,經過 /bin/bash 的解析,能夠當即獲得 Shell 的迴應
[root@mico ~]# echo "hello"
hello
[root@mico ~]# pwd
/root
[root@mico ~]#
  • 非交互的方式: 腳本

什麼是Shell腳本

  • Linux命令、變量和流程控制語句等有機的結合起來並以程序文件形式執行,該程序稱爲shell腳本。
  • Shell腳本語言是弱類型語言(無須定義變量的類型便可使用), shell腳本擅長處理純文本類型的數據,而linux中,幾乎全部的配置文件,日誌,都是純文本類型文件。

腳本語言的種類

編譯型語言

定義:指用專用的編譯器,針對特定的操做平臺(操做系統)將某種高級語言源代碼一次性翻譯成可被硬件平臺直接運行的二進制機器碼(具備操做數,指令、及相應的格式),這個過程叫作編譯(./configure  make makeinstall );編譯好的可執行性文件(.exe),可在相對應的平臺上運行(移植性差,但運行效率高)。典型的編譯型語言有, C語言、C++等。另外,Java語言是一門很特殊的語言,Java程序須要進行編譯步驟,但並不會生成特定平臺的二進制機器碼,它編譯後生成的是一種與平臺無關的字節碼文件(*.class)(移植性好的緣由),這種字節碼天然不能被平臺直接執行,運行時須要由解釋器解釋成相應平臺的二進制機器碼文件;大多數人認爲Java是一種編譯型語言,但咱們說Java便是編譯型語言,也是解釋型語言也並無錯。

解釋型語言

定義:指用專門解釋器對源程序逐行解釋成特定平臺的機器碼並當即執行的語言;至關於把編譯型語言的編譯連接過程混到一塊兒同時完成的。解釋型語言執行效率較低,且不能脫離解釋器運行,但它的跨平臺型比較容易,只需提供特定解釋器便可。常見的解釋型語言有, Python(同時是腳本語言)與Ruby等。

腳本語言

定義:爲了縮短傳統的編寫-編譯-連接-運行(edit-compile-link-run)過程而建立的計算機編程語言。
    特色:程序代碼便是最終的執行文件,只是這個過程須要解釋器的參與,因此說腳本語言與解釋型語言有很大的聯繫。腳本語言一般是被解釋執行的,並且程序是文本文件。

典型的腳本語言有,JavaScript,Python,shell等。java

其餘經常使用的腳本語句種類

  • PHP是網頁程序,也是腳本語言。是一款更專一於 web 頁面開發(前端展現)的腳本語言,例如:Dedecms,discuz。PHP 程序也能夠處理系統日誌,配置文件等,php 也能夠調用系統命令。
  • Perl 腳本語言。比 shell 腳本強大不少,語法靈活、複雜,實現方式不少,不易讀,團隊協做困難,但仍不失爲很好的腳本語言,存世大量的程序軟件。MHA 高可用 Perl 寫的
  • Python,不但能夠作腳本程序開發,也能夠實現 web 程序以及軟件的開發。近兩年愈來愈多的公司都會要求會 Python。

Shell腳本與 php/perl/python 語言的區別和優點?

shell 腳本的優點在於處理操做系統底層的業務 (linux 系統內部的應用都是 shell 腳本完成)由於有大量的 linux 系統命令爲它作支撐。2000 多個命令都是 shell 腳本編程的有力支撐,特別是grep、awk、sed 等。例如:一鍵軟件安裝、優化、監控報警腳本,常規的業務應用,shell 開發更簡單快速,符合運維的簡單、易用、高效原則。PHP、Python 優點在於開發運維工具以及 web 界面的管理工具,web 業務的開發等。處理一鍵軟件安裝、優化,報警腳本。常規業務的應用等 php/python 也是可以作到的。可是開發效率和複雜比用 shell 就差不少了。python

系統中的shell

查看系統環境

[root@mico ~]# cat /etc/redhat-release 
CentOS Linux release 7.5.1804 (Core) 
[root@mico ~]# uname -r
3.10.0-862.11.6.el7.x86_64
[root@mico ~]# getenforce 
Disabled
[root@mico ~]# systemctl status firewalld.service 
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:firewalld(1)
[root@mico ~]#

查看系統中的命解釋器

[root@mico ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
[root@mico ~]#

經常使用操做系統的默認shell

  • Linux是Bourne Again shell(bash)
  • Solaris和FreeBSD缺省的是Bourne shell(sh)
  • AIX下是Korn Shell(ksh)
  • HP-UX缺省的是POSIX shell(sh)
[root@mico ~]# echo $SHELL
/bin/bash

查看系統的 Bash 版本

[root@VM_42_34_centos /]# head -1 /etc/init.d/network 
#! /bin/bash
[root@VM_42_34_centos /]# head -1 /etc/init.d/netconsole 
#!/bin/bash

bash版本

[root@mico ~]# bash -version
GNU bash, 版本 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
許可證 GPLv3+: GNU GPL 許可證版本3或者更高 <http://gnu.org/licenses/gpl.html>

這是自由軟件,您能夠自由地更改和從新發布。
在法律容許的範圍內沒有擔保.

bash 破殼漏洞

使用 命令 env x='() { :;}; echo be careful' bash -c "echo this is a test"
若是返回結果爲一行,則爲正常,linux

[root@mico ~]# env x='() { :;}; echo be careful' bash -c "echo this is a test"
this is a test
#解決辦法 升級當前的bash版本
 yum install update bash

bash 和 sh 的區別

早期的bash和sh稍有不一樣,還包含了csh和ksh的特點,但大多數腳本均可以不加修改地在sh上運行web

[root@VM_42_34_centos ~]# ll /bin/bash
-rwxr-xr-x 1 root root 964544 4月  11 2018 /bin/bash
[root@VM_42_34_centos ~]# ll /bin/sh
lrwxrwxrwx 1 root root 4 8月  10 2018 /bin/sh -> bash

說明:sh爲bash的軟連接,通常狀況下,腳本開頭使用「#!/bin/bash」和"#!/bin/sh"是沒有區別的,但更規範的寫法是在腳本開頭使用「#!/bin/bash」
下面的Shell腳本是系統自帶的軟件啓動腳本的開頭部分面試

sh與bash 的關係

[root@mico ~]# ll /bin/sh
lrwxrwxrwx 1 root root 4 8月  10 2018 /bin/sh -> bash

/bin與 /user/bin 的關係

[root@mico ~]# ll /bin -d
lrwxrwxrwx 1 root root 7 8月  10 2018 /bin -> usr/bin

腳本書寫規範

腳本統一存放目錄

[root@mico ~]# mkdir -p /server/scripts/
[root@mico ~]# cd /server/scripts/

選擇解釋器

腳本第一行指出由哪一個程序(解釋器)來執行腳本中的內容
#!/bin/bash#!/bin/sh (255個字符之內)shell

注意格式 ↓
其中開頭的"#!"字符又稱爲幻數,在執行bash腳本的時候,內核會根據"#!"後的解釋器來肯定該用那個程序解釋這個腳本中的內容。編程

[root@mico scripts]# head -1 /etc/init.d/*
==> /etc/init.d/functions <==
# -*-Shell-script-*-

==> /etc/init.d/netconsole <==
#!/bin/bash

==> /etc/init.d/network <==
#! /bin/bash

==> /etc/init.d/README <==
You are looking for the traditional init scripts in /etc/rc.d/init.d,

編輯腳本使用vim

使用 .vimrc 文件,將下面的信息添加到 .vimrc 文件中,可以快速的生成開頭的註釋信息

autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"

func SetTitle()
    if expand("%:e") == 'sh'
        call setline(1,"#!/bin/bash")
        call setline(2, "##############################################################")
        call setline(3, "# File Name: ".expand("%"))
        call setline(4, "# Version: V1.0")
        call setline(5, "# Author: mico")
        call setline(6, "# Created Time : ".strftime("%F %T"))
        call setline(7, "# Description:")
        call setline(8, "##############################################################")
        call setline(9, "")
    endif
endfunc

使用後的效果

#!/bin/bash
##############################################################
# File Name: scripts_tmp.sh
# Version: V1.0
# Author: mico
# Created Time : 2019-07-09 10:12:27
# Description:
##############################################################

在Shell腳本中,跟在#後面的內容表示註釋。註釋部分不會被執行,僅給人看。註釋能夠自成一行,也能夠跟在命令後面,與命令同行。要養成寫註釋的習慣,方便本身與他人。
最好不用中文註釋,由於在不一樣字符集的系統會出現亂碼。(字符集爲zh_CN.UTF-8,爲中文)。

文件名規範

名字要有意義,而且結尾以 .sh 結束(並非必須)

開發的規範和習慣小結

  • 放在統一的目錄
  • 腳本以 .sh 爲擴展名
  • 開頭指定腳本解釋器。
  • 開頭加版本版權等信息,可配置 ~/.vimrc 文件自動添加。
  • 腳本不要用中文註釋,儘可能用英文註釋。
  • 代碼書寫優秀習慣
    • 成對的內容一次性寫出來,防止遺漏,如[ ]' '" "
    • [ ] 兩端要有空格,先輸入[ ],退格,輸入 2 個空格,再退格寫。
    • 流程控制語句一次書寫完,再添加內容。(if 條件 ; then 內容;fi)
    • 經過縮進讓代碼易讀。
    • 腳本中的引號都是英文狀態下的引號,其餘字符也是英文狀態。

shell腳本的執行

當 Shell 腳本運行時,會先查找系統環境變量 ENV,該變量指定了環境文件(加載順序一般是 /etc/profile~/.bash_profile~/.bashrc/etc/bashrc ),在加載了上述變量文件後,Shell就開始執行腳本中的內容。

Shell 腳本是從上至下、從左至右依次執行每一行的命令及語句的。即執行完了一個命令後再執行下一個,若是在 Shell 腳本中(即腳本嵌套)
時,就會先執行子腳本的內容,完成後再返回父腳本繼續執行父腳本內後序的命令及語句。
一般狀況下,在執行 Shell 腳本時,會向系統內核請求啓動一個新進程,以便在該進程或只能怪執行腳本的命令以及子Shell 腳本。

執行腳本的辦法

執行腳本的四種方法

(1)sh/bash scripts.sh
當腳本自己沒有可執行權限時使用的方法,或腳本文件開頭沒有指定解釋器時須要使用分方法。
(2)首先chown +x ,而後./scripts.sh .path/scripts.sh
在當前路徑下執行腳本(腳本須要有執行權限),經過絕對路徑或相對路徑直接執行腳本
(3)source scripts.sh. (空格) scripts.sh
這種方法一般是使用 source. 讀入或加載指定的 shell 腳本文件(不須要執行權限),而後依次執行指定 shell 腳本中的全部語句。這些語句將在當前 shell 腳本的進程中運行(其餘幾種模式都會啓動新的進程執行子腳本)。source. 命令的功能是在當前 Shell 中執行 source. 加載並執行的相關腳本文件中的命令及語句,而不是產生一個子 Shell 來執行文件中的命令。
說明.source 命令的功能相同,都是讀入腳本並執行腳本中的命令。
(4)sh < script-name 或 cat scripts-name|sh 效率低
一樣適用於bash,不過這種用法不常見。

source 與 . (點) 的做用

soucre命令

[root@mico ~]# help source  |head -2
source: source 文件名 [參數]
    在當前 shell 中執行一個文件中的命令。
. (點)
[root@mico ~]# help . |head -2
.: . 文件名 [參數]
    在當前 shell 中執行一個文件中的命令。

sh於source的區別

對比:用 source 執行腳本文件,執行過程不另開進程,腳本文件中設定的變量在當前shell中能夠看到;
用 sh/bash 執行腳本文件,是在當前進程另開子進程來執行腳本命令,腳本文件中設定的變量在當前shell中不能看到。

例如

[root@VM_42_34_centos trsky]# echo 'userdir=`pwd`' >> testsource.sh
[root@VM_42_34_centos trsky]# cat testsource.sh 
userdir=`pwd`
[root@VM_42_34_centos trsky]# sh testsource.sh 
[root@VM_42_34_centos trsky]# echo $userdir

[root@VM_42_34_centos trsky]# source testsource.sh 
[root@VM_42_34_centos trsky]# echo $userdir
/home/trsky
[root@VM_42_34_centos trsky]#

由案例可知,使用 source. 執行的腳本中的變量值會傳遞到當前的 Shell 下,由於使用 source. 執行腳本不會開啓新的進程,而是在統一進程下完成腳本中全部指令的執行。

[root@mico scripts]# sh  mico_test.sh 
Hello World!
[root@mico ~]# echo $Mico
Mico #  sh  新建一個Shell窗口(新建一個進程)執行一個文件中的命令。

[root@mico scripts]# source mico_test.sh 
Hello World!
[root@mico scripts]# echo $mico
Hello World!

面試題:

問 sh test.sh 後 echo $user 返回的結果__空_ ?

[root@oldboy scripts]# cat test.sh 
#!/bin/bash
user=`whoami`

Shell的變量

Shell變量的特性

Shell爲弱類型語言,因此在默認狀況下,在Bash Shell中是不會區分變量類型的。但Shell能夠通 declare 顯示定義變量的類型。

什麼是變量

變量能夠分爲兩類:環境變量(全局變量)和普通變量(局部變量)

  • 環境變量也可稱爲全局變量,能夠在建立他們的Shell及其派生出來的任意子進程shell中使用,環境變量又可分爲自定義環境變量和Bash內置的環境變量
  • 普通變量也可稱爲局部變量,只能在建立他們的Shell函數或Shell腳本中使用。普通變量通常是由開發者用戶開發腳本程序時建立的。
  • 特殊變量

Shell中定義變量名以及爲變量內容賦值要求
變量名通常由字母、數字、下劃線組成,能夠由字母或下劃線開頭

把一個命令的結果做爲變量的內容賦值的方法

  • 變量名=ls
  • 變量名=$(ls)

環境變量

使用 env/declare/set/export -p 命令查看系統中的環境變量,這三個命令的的輸出方式稍有不一樣。

[root@mico scripts]# env
XDG_SESSION_ID=1
HOSTNAME=mico
TERM=linux
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=10.0.0.1 5537 22
SSH_TTY=/dev/pts/0
USER=root
~~~

輸出一個系統中的環境變量

[root@mico ~]# echo $LANG
zh_CN.UTF-8

自定義環境變量

設置環境變量
exportdeclare

設置環境變量的3種方法

  • export 變量名=value
  • 變量名=value; export 變量名
  • declare -x 變量名=value

自定義全局變量的實例:

[root@VM_42_34_centos ~]# cat /etc/profile|grep Mico
export Mico='mico'
[root@VM_42_34_centos ~]# source /etc/profile
[root@VM_42_34_centos ~]# echo $MIco

[root@VM_42_34_centos ~]# echo $Mico
mico
[root@VM_42_34_centos ~]# env|grep Mico
Mico=mico
[root@VM_42_34_centos ~]#

讓環境變量永久生效的經常使用設置文件

  • 用戶環境變量配置
# 用戶的環境變量設置,比較常見的是用戶家目錄下的.bashrc 和 .bash_profile
[root@mico ~]# ls /root/.bashrc
/root/.bashrc
[root@mico ~]# ls /root/.bash_profile 
/root/.bash_profile
[root@mico ~]#
  • 全局環境變量的配置
    常見的全局環境變量的配置文件以下:
/etc/profile
/etc/bashrc
/etc/profile.d/

若是要在登錄後初始化或顯示加載內容,則將腳本文件放在/etc/profile.d/下便可(無需執行權限)

設置登陸提示的兩種方式

  • /etc/motd裏增長提示的字符串
[root@mico ~]# vim /etc/motd
[root@mico ~]# cat /etc/motd 
Welcome to Linux.
  • /etc/profile.d/目錄下添加腳本
[root@mico profile.d]# cat /etc/profile.d/mico.sh 
#!/bin/bash
##############################################################
# File Name: /etc/profile.d/mico.sh
# Version: V1.0
# Author: mico
# Created Time : 2019-07-01 10:00:06
# Description:
##############################################################
echo "Hello, you are studing Linux"

登陸後出現

Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.

Welcome to Linux.
Hello, you are studing Linux
[root@mico ~]#

顯示與取消環境變量

  • 經過 echo 或 prinf 打印環境變量
#常見的系統環境變量
$HOME:用戶登陸時進入的目錄
$UID:當前用戶的UID(用戶標識),至關於 id-u
$PWD:當前工做目錄的絕對路徑名
$SHELL:當前Shell
$USER:當前yonghu
...
打印或刪除環境變量
#打印環境
printf "$Home\n"
echo $PWD
  • 使用unset取消環境變量
#刪除環境變量
unset PWD

普通變量

本地變量在用戶當前的Shell生存期的腳本中使用。例如,本地變量OLDBOY取值爲bingbing,這個值在用戶當前Shell生存期中有意義。若是在Shell中啓動另外一個進程或退出,本地變量值將無效

普通變量的定義

變量名=value    //解釋變量名
變量名='value'  //不解釋變量名
變量名="value"  //解釋變量名

定義普通變量實踐

[root@mico ~]# a=1
[root@mico ~]# b='2'
[root@mico ~]# c="3"
[root@mico ~]# echo "$a"
1
[root@mico ~]# echo "$b"
2
[root@mico ~]# echo "${c}"

提示:$變量名錶示輸出變量,能夠用$c和${c}兩種用法
【小結】連續普通字符串內容賦值給變量,無論用什麼引號或者不用引號,它的內容是什麼,打印變量就輸出什麼

export命令

[root@mico ~]# help export 
export: export [-fn] [名稱[=值] ...] 或 export -p
爲 shell 變量設定導出屬性。

標記每一個 NAME 名稱爲自動導出到後續命令執行的環境。若是提供了 VALUE
則導出前將 VALUE 做爲賦值。

export命令的說明

  • 當前shell窗口及子shell窗口生效
  • 在新開的shell窗口不會生效,生效須要寫入配置文件

定義變量

[root@mico scripts]# CSLN=mico
[root@mico scripts]# export CSLN1=1
# 當前窗口查看
[root@mico scripts]# echo $CSLN
mico
[root@mico scripts]# echo $CSLN1
1
# 編寫測試腳本
[root@mico scripts]# vim quanju.sh 
#!/bin/bash
echo $CSLN
echo $CSLN1
# 使用sh執行
[root@mico scripts]# sh  quanju.sh 

1
# 使用source 執行
[root@mico scripts]# source quanju.sh 
mico
1

環境變量相關配置文件

  • /etc/proflie
  • /etc/bashrc
  • ~/.bashrc
  • ~/.bash_profile
  • /etc/proflie.d/ # 目錄

四文件讀取順序(CentOS6和7都同樣)

① /etc/profile
② ~/.bash_profile
③ ~/.bashrc
④ /etc/bashrc

系統運行Shell的三種方式

1) 經過系統用戶登錄後默認運行的shell
2) 非登陸交互式運行Shell
3) 執行腳本運行非交互式Shell

文件讀取過程示意圖

驗證四文件讀取順序的方法

sed -i '1a echo "$(date +%T-%s) /etc/profile1" >>/tmp/mico' /etc/profile
sed -i '$a echo "$(date +%T-%s) /etc/profile2" >>/tmp/mico' /etc/profile
sed -i '1a echo "$(date +%T-%s) /etc/bashrc1" >>/tmp/mico' /etc/bashrc
sed -i '$a echo "$(date +%T-%s) /etc/bashrc2" >>/tmp/mico' /etc/bashrc
sed -i '1a echo "$(date +%T-%s) ~/.bashrc1" >>/tmp/mico' ~/.bashrc
sed -i '$a echo "$(date +%T-%s) ~/.bashrc2" >>/tmp/mico' ~/.bashrc
sed -i '1a echo "$(date +%T-%s) ~/.bash_profile1" >>/tmp/mico' ~/.bash_profile
sed -i '$a echo "$(date +%T-%s) ~/.bash_profile2" >>/tmp/mico' ~/.bash_profile

環境變量的知識小結

  • 變量名一般要大寫。
  • 變量能夠在自身的Shell及子Shell中使用。
  • 經常使用export來定義環境變量。
  • 執行env默承認以顯示全部的環境變量名稱及對應的值。
  • 輸出時用「$變量名」,取消時用「unset變量名」。
  • 書寫crond定時任務時要注意,腳本要用到的環境變量最好先在所執行的Shell腳本中從新定義。
  • 若是但願環境變量永久生效,則能夠將其放在用戶環境變量文件或全局環境變量文件裏。

環境變量

環境變量通常是指用export內置命令導出的變量,用戶定義shell的運行環境。保證shell命令的正確執行。Shell經過環境變量來肯定登陸用戶名、命令路徑、終端類型、登陸目錄等。若是須要永久保存環境變量,可在用戶家目錄下的.bash_profile或.bashrc(非用戶登陸模式特有,例如遠程登陸SSH)文件中,或者全局配置/etc/bashrc(非用戶登陸模式特有,如遠程SSH)或/etc/profile文件中定義。在將環境變量放入上述的文件以後,每次用戶登陸時這些變量將被初始化。

查看設置的變量:set、env、declare

  • set:輸出全部的變量,包括全局變量和局部變量。set -o 顯示bash Shell的全部參數配置信息
  • env:只顯示全局變量
  • declare:輸出全部的變量、函數、整數和已經導出的變量

變量中引號的使用

  • 只有在變量的值中有空格的時候,會使用引號。
  • 單引號與雙引號的區別在於,是否可以解析特殊符號。
[root@mico ~]# name=vicodona
[root@mico ~]# name2='mico'
[root@mico ~]# name3="you are my heart"
[root@mico ~]# echo $name
vicodona
[root@mico ~]# echo $name2
mico
[root@mico ~]# echo $name3
you are my heart
[root@mico ~]# name4='mi co'
[root@mico ~]# echo $name4
mi co
[root@mico ~]# name5="mi co"
[root@mico ~]# echo $name5
mi co
[root@mico ~]# name6="mico $PWD"
[root@mico ~]# echo $name6
mico /root
[root@mico ~]# name6='mi co $PWD'
[root@mico ~]# echo $name6
mi co $PWD
[root@mico ~]# name7="mico $PWD"
[root@mico ~]# echo $name7
mico /root

普通變量的要求

  • 內容是純數字、簡單的連續字符(內容中不帶任何空格)時,定義時能夠不加任何引號,例如:
a.MicoAge=22
b.NETWORKING=yes
  • 沒有特殊狀況時,字符串一概用雙引號定義賦值,特別是多個字符串中間有空格時,例如:
a.NFSD_MODULE="no load"
b.MyName="Oldboy is a handsome boy."
  • 當變量裏的內容須要原樣輸出時,要用單引號(M),這樣的需求極少,例如:
a.OLDBOY_NAME='OLDBOY'

變量使用反引號賦值

[root@mico scripts]# time=`date`
[root@mico scripts]# echo $time
2017年 12月 05日 星期二 09:02:06 CST
    
[root@mico scripts]# file=`ls`
[root@mico scripts]# echo $file
mico_test.sh panduan.sh quanju.sh yhk.sh

使用${}

打印變量的時候防止出現「金庸新著」的問題

[root@mico ~]# time=`date`
[root@mico ~]# echo $time
2019年 07月 18日 星期四 17:47:23 CST
[root@mico ~]# echo ${time}_day
2019年 07月 18日 星期四 17:47:23 CST_day
[root@mico ~]# echo $time-day
2019年 07月 18日 星期四 17:47:23 CST-day

編寫腳本測試${}

# 使用腳本測試
 [root@mico ~]# vim variable.sh 
 #!/bin/bash
    
 time=`date`
 echo $timeday
 echo ${time}day
    
[root@mico ~]# sh variable.sh 

2019年 07月 18日 星期四 17:49:51 CSTday
名稱 解釋
單引號 所見即所得,即輸出時會將單引號內的全部內容都原樣輸出,或者描述爲單引號裏面看到的是什麼就會輸出什麼;這稱爲強引用
雙引號(默認) 輸出雙引號內的全部內容;若是內容中有命令、變量、特殊字符等,會先把變量、命令、轉義字符解析出結果,而後再輸出最終內容,推薦使用,稱爲弱引用
無引號 賦值時,若是變量內容中有空格,則會形成賦值不完整。而在輸出內容時,會將含有空格的字符串視爲一個總體來輸出;若是內容中有命令、變量等,則會先把變量、命令解析出結果,而後輸出最終內容;若是字符串中帶有空格等特殊字符,則有可能沒法完整的輸出,所以須要改加雙引號
反引號 通常用於引用命令,執行的時候命令會被執行,至關於`$()`,賦值和輸出都要用命令引發來

定義變量名技巧

  • 變量名只能爲字母、數字或下劃線,只能以字母或下劃線開頭。
  • 變量名的定義要有必定的規範,而且要見名知意。

示例:

MicoAge=22       #<==每一個單詞的首字母大寫的寫法
mico_age=22      #<==單詞之間用"_"的寫法
micoAgeSex=man   #<==駝峯語法:首個單詞的首字母小寫,其他單詞首字母大寫
MICOAGE=22       #<==單詞全大寫的寫法
  • 通常的變量定義、賦值經常使用雙引號;簡單連續的字符串能夠不加引號;但願原樣輸出時使用單引號。
  • 但願變量的內容是命令的解析結果時,要用反引號'',或者用$()把命令括起來再賦值。

特殊變量

位置變量

經常使用的特殊位置參數說明

位置變量 做用說明
$0 獲取當前執行的shell腳本的文件名,若是執行腳本帶路徑那麼就包括腳本路徑。
$n 獲取當前執行的shell腳本的第n個參數值,n=1..9,當n爲0時表示腳本的文件名,若是n大於9用大括號括起來{10},參數以空格隔開。
$# 獲取當前執行的shell腳本後面接的參數的總個數
$* 獲取當前shell的全部傳參的參數,不加引號同$@;若是給$加上雙引號,例如: 「$」,則表示將全部的參數視爲單個字符串,至關於「112$3」。
$@ 獲取當前shell的全部傳參的參數,不加引號同$*;若是給$@加上雙引號,例如: 「$@」,則表示將全部參數視爲不一樣的獨立字符串,至關於「$1」 「$2」 「$3」 「……」,這是將參數傳遞給其餘程序的最佳方式,由於他會保留全部內嵌在每一個參數裏的任何空白。

$*$@ 都加雙引號時,二者有區別,都不加雙引號時,二者無區別。

舉例說:
腳本名稱叫 test.sh 入參三個: 1 2 3
運行 test.sh 1 2 3後
$* 爲 "1 2 3"(一塊兒被引號包住)
$@ 爲 "1" "2" "3"(分別被包住)

參數實踐
[root@mico ~]# vim parameter.sh
#!/bin/bash
    
echo $0
echo "第一個參數:" $1
echo "第二個參數:" $2
echo "第11個參數:" ${11}

[root@mico ~]# sh parameter.sh 
parameter.sh
第一個參數:
第二個參數:
第11個參數:
[root@mico ~]# 
[root@mico ~]# sh parameter.sh 1 2 3 4 5 6 7 8 9 10 11
parameter.sh
第一個參數: 1
第二個參數: 2
第11個參數: 11
[root@mico ~]#
$# 參數實踐
[root@mico ~]# cat parameter.sh 
#!/bin/bash
##############################################################
# File Name: parameter.sh
# Version: V1.0
# Author: mico
# Created Time : 2019-07-18 17:50:45
# Description:
##############################################################
echo $0
echo "第一個參數:" $1
echo "第二個參數:" $2
echo "第10個參數:" ${10}
echo "第11個參數:" ${11}
echo "參數個數:" $#

[root@mico ~]# sh parameter.sh 1 2 3 4 5 6 7 8 9 10 11
parameter.sh
第一個參數: 1
第二個參數: 2
第10個參數: 10
第11個參數: 11
參數個數: 11
$* 參數實踐
[root@mico ~]# vim parameter.sh

#!/bin/bash
##############################################################
# File Name: parameter.sh
# Version: V1.0
# Author: mico
# Created Time : 2019-07-18 17:50:45
# Description:
##############################################################
echo $0
echo "第一個參數:" $1
echo "第二個參數:" $2
echo "第10個參數:" ${10}
echo "第11個參數:" ${11}
echo "參數個數:" $#
echo "參數:"$*                               
[root@mico ~]# sh parameter.sh 1 2 3 4 5 6 7 8 9 10 11
parameter.sh
第一個參數: 1
第二個參數: 2
第10個參數: 10
第11個參數: 11
參數個數: 11
參數:1 2 3 4 5 6 7 8 9 10 11
$*$@ 對比實踐
[root@mico scripts]# set -- "I am" handsome boy..
[root@mico scripts]# echo $1
I am
[root@mico scripts]# echo $2
handsome
[root@mico scripts]# echo $3
boy..
[root@mico scripts]# echo $*
I am handsome boy..
[root@mico scripts]# echo $@
I am handsome boy..

[root@mico scripts]# for i in $*;do echo $i ;done
I
am
handsome
boy..
[root@mico scripts]# for i in $@;do echo $i ;done
I
am
handsome
boy..
[root@mico scripts]# for i in "$@";do echo $i ;done
I am
handsome
boy..
[root@mico scripts]# for i in "$*";do echo $i ;done
I am handsome boy..

進程狀態變量

Shell進程的特殊狀態變量說明

位置變量 做用說明
$? 獲取執行上一個指令的執行狀態返回值(0爲成功,非零爲失敗),這個變量最經常使用
$$ 獲取當前執行的Shell腳本的進程號(PID),這個變量不經常使用,瞭解便可
$! 獲取上一個在後臺工做的進程的進程號(PID),這個變量不經常使用,瞭解便可
$_ 獲取在此以前執行的命令或腳本的最後一個參數,這個變量不經常使用,瞭解便可

進程參數實踐

[root@mico scripts]# echo $?
0
[root@mico scripts]# echo $$
1368
[root@mico scripts]# echo $!

[root@mico scripts]# echo $_
Echo

Bash Shell常見的內部命令:echoevalexecexportreadshift

echo參數說明

參數 參數說明
-n 不要追加換行
-e 啓用下列反斜槓轉義的解釋
-E 顯式地抑制對於反斜槓轉義的解釋

`echo' 對下列反斜槓字符進行轉義:

  • \n:換行
  • \r:回車
  • \t:橫向製表符
  • \b:退格
  • \v:縱向製表符
  • \c:抑制更多的輸出

定義變量的方式

三種定義變量的方式

  • 直接賦值
  • 傳參 (傳遞參數)
  • 交互式設置變量,使用read命

read命令說明

在命令行中使用

[root@mico scripts]# read
132
[root@mico scripts]# echo $REPLY 
132
[root@mico scripts]# read mico 
456
[root@mico scripts]# echo $mico
456
[root@mico scripts]# echo $REPLY 
132

在腳本中使用

[root@mico scripts]# vim mico_test.sh 
#!/bin/bash
read -p '請輸入:'  mico

echo $mico
執行結果
[root@mico scripts]# sh mico_test.sh 
請輸入:mico_znix
mico_znix

read 命令的幫助說明

[root@mico scripts]# read --help
-bash: read: --: 無效選項
read: 用法:read [-ers] [-a 數組] [-d 分隔符] [-i 緩衝區文字] [-n 讀取字符數] [-N 讀取字符數] [-p 提示符] [-t 超時] [-u 文件描述符] [-s不顯示終端的任何輸入] [名稱 ...]

定義方法實踐

直接賦值方法

[root@mico ~]# cat parameter.sh 
#!/bin/bash
##############################################################
# File Name: parameter.sh
# Version: V1.0
# Author: mico
# Created Time : 2019-07-18 17:50:45
# Description:
##############################################################
name=MICO
age=18
sex=girl
hobby=`ls`
ethFile=/etc/sysconfig/network-scripts/ifcfg-eth0

echo $hobby
ls $ethFile
[root@mico ~]# sh parameter.sh 
default.pass Django-Blog Django-Blog.tar parameter.sh practices scripts server test.sh variable.sh
/etc/sysconfig/network-scripts/ifcfg-eth0

交互式設置變量 read

[root@mico ~]# vim keyword.sh 
#!/bin/bash
##############################################################
# File Name: keyword.sh
# Version: V1.0
# Author: mico
# Created Time : 2019-07-18 18:42:31
# Description:
##############################################################
read -p "請輸入您的學號:" number
read -s -p "請輸入姓名:" name
echo
echo "您的學號:"$number
echo "您的姓名:"$name
[root@mico ~]# sh keyword.sh 
請輸入您的學號:20190729
請輸入姓名:
您的學號:20190729
您的姓名:youka

寫一個交互腳本,實現可以定義主機名及IP地址

腳本內容↓

[root@mico ~]# cat keyword.sh 
#!/bin/bash
##############################################################
# File Name: keyword.sh
# Version: V1.0
# Author: mico
# Created Time : 2019-07-18 18:42:31
# Description:
##############################################################
read -p "請輸入您的學號:" number
read -s -p "請輸入姓名:" name
echo
echo "您的學號:"$number
echo "您的姓名:"$name

[root@mico ~]# vim host_start.sh
[root@mico ~]# sh host_start.sh 
請輸入主機名:mico
請輸入IP地址的主機位:180
是否重啓服務器:{yes/no}no
請稍後手動重啓系統!

變量的子串

變量子串說明

表達式 說明
${parameter} 返回變量$parameter的內容
${#parameter} 返回變內容的長度(按字符),也適用於特殊變量
${parameter:offset} 在變量${parameter}中,從位置offset以後開始提取子串到結尾
${parameter:offset:length} 在變量${parameter}中,從位置offset以後開始提取長度爲length的子串
${parameter#word} 從變量${parameter}開頭開始刪除最短匹配的word子串
${parameter##word} 從變量${parameter}開頭開始刪除最長匹配的word子串
${parameter%word} 從變量${parameter}結尾開始刪除最短匹配的word子串
${parameter%%word} 從變量${parameter}結尾開始刪除最長匹配的word子串
${parameter/pattem/string} 使用string代替第一個匹配的pattern
${parameter//pattem/string} 使用string代替全部匹配的pattern

計算變賦值的長度

  • echo $(#Mico) :這種方式最快
  • echo $Mico|wc -L
  • expr length "$Mico"
  • echo "$Mico"|awk '{print length($0)}'
[root@mico ~]# export TEMP="Here is Linux"
[root@mico ~]# echo ${#TEMP}
13
[root@mico ~]# echo $TEMP|wc -L
13
[root@mico ~]# expr length "$TEMP"
13
[root@mico ~]# echo "$TEMP"
Here is Linux
[root@mico ~]# echo "$TEMP"|awk '{print length($0)}'
13
[root@mico ~]# time echo ${#TEMP}
13

real	0m0.000s
user	0m0.000s
sys	0m0.000s
[root@mico ~]# time echo $TEMP|wc -L
13

real	0m0.002s
user	0m0.000s
sys	0m0.002s
[root@mico ~]#

截取變量中的字符

[root@mico scripts]# mico=abcABC123ABCabc
[root@mico scripts]# echo ${mico#abc}
ABC123ABCabc
[root@mico scripts]# echo ${mico##abc}
ABC123ABCabc
[root@mico scripts]# echo ${mico%abc}
abcABC123ABC
[root@mico scripts]# echo ${mico%%abc}
abcABC123ABC
[root@mico scripts]# echo ${mico#a*c}
ABC123ABCabc
[root@mico scripts]# echo ${mico##a*c}

[root@mico scripts]# echo ${mico%a*c}
abcABC123ABC
[root@mico scripts]# echo ${mico%%a*c}

[root@mico scripts]# echo ${mico#a*C}
123ABCabc
[root@mico scripts]# echo ${mico#a*C}
123ABCabc
[root@mico scripts]# echo ${mico##a*C}
abc
[root@mico scripts]# echo ${mico%a*c}
abcABC123ABC
[root@mico scripts]# echo ${mico%A*c}
abcABC123
[root@mico scripts]# echo ${mico%%A*c}
abc

替換變量內容

[root@mico scripts]# echo $mico
abcABC123ABCabc
[root@mico scripts]# echo ${mico/abc/mico}
micoABC123ABCabc
[root@mico scripts]# echo ${mico//abc/mico}
micoABC123ABCmico

echo $(#parameter) 處理最快的緣由是通常狀況下調用外部命令來處理的方式與使用內置操做的速度相差較大。在Shell編程中應該儘可能使用內置命令。

有關獲取字符串長度的幾種統計方法的性能比較

  • 變量自帶的計算長度的方法效率最高,在要求效率的場景中儘可能多用
  • 使用管道統計的方法的效率都比較差,在要求效率的場景中儘可能不用
  • 對於平常簡單的腳本計算,能夠根據本身所擅長的或易用的程度去選擇

有關上述匹配刪除的小結

+#表示從幵頭刪除匹配最短。

  • ##表示從開頭刪除匹配最長。
  • %表示從結尾刪除匹配最短。
  • %%表示從結尾刪除匹配最長。
  • a*c表示匹配的突符串,*表示匹配全部,a*c 匹配開頭爲 a、中間爲任意多個字符、結尾爲c的字符串。
  • a*C表示匹配的字符串,*表示匹配全部,a*C 匹配開頭爲 a、中間爲任意多個字符、結尾爲C的字符串。

有關替換的小結

  • 一個「/」表示替換匹配的第-個字符串。
  • 兩個「/」表示替換匹配的全部字符串。

Shell的特殊擴展變量說明

表達式 說明
${parameter:-word} 若是parameter的變量值爲空或未賦值,則會返回word字符串並替代變量的值用途.若是變量未定義,則返回備用的值,防止變量爲空值或因未定義而致使異常
${parameter:=word} 若是parameter的變量值爲空或未賦值,則設置這個變量值爲word,並返回其值。位置變量和特殊變量不適用用途:基本同上一個${parameter>word},但該變量又額外給parameter變量賦值了
${parameter:?word} 若是parameter變量值爲空或未賦值,那麼word字符串將被做爲標準錯誤輸出,不然輸出變量的值。用途:用於捕捉因爲變量未定義而致使的錯誤,並退出程序
${parameter:+word} 若是parameter變量值爲空或未賦值,則什麼都不作,不然word字符串將替代變量的值

變量的數值計算

Shell中常見的算術運算符號

運算符 意義 順序
++ - - 增長及減小,可前置/可結尾
+ 一元正號
- 一元負號
邏輯與
~ 位的取反
* / % 乘法、除法、取餘數
+ 加法
- 減法
<< >> 向左位移、向右位移
< <= > >= 比較運算符
== != 相等 不相等
& 位的AND
^ 位的Exclusive OR
| 位的OR
&& 邏輯AND
|| 邏輯OR
?: 條件表達式
= += -= *= /= %= &= ^= 賦值運算符

Shell中常見的算術運算命令

運算操做符與運算命令 意義
(()) 用於整數運算的經常使用運算符,效率高
let 用於整數運算,相似於"(())"
expr 可用於整數運算,但還有不少其餘的額外功能
bc Linux下的一個計算器程序(適合整數以及小數運算)
$[] 用於整數的運算
awk awk既能夠用於整數運算,也能夠用於小數運算
declare 定義變量值和屬性,-i參數能夠用於定義整形變量,作運算

雙小括號(())的操做方法

運算操做符與運算命令 意義
((i=i+1)) 此種書寫方法爲運算後賦值法,即將i+1的運算結構賦值給變量i。注意,不能用"echo((i=i+1))"的形式輸出表達式的值,但能夠用echo$((i=i+1))輸出其值
i=$((i+1)) 能夠在"(())"前加$符,表示將表達式運算後複製給i
((8>7&&5==5)) 能夠進行比較操做,還能夠加入邏輯與和邏輯或,用於條件判斷
echo $((2+1)) 須要直接輸出運算表達式的運算結果時,能夠在"(())"前加$符

【提示】上面涉及的數字及變量必須爲整數(整型),不能是小數(浮點數)或字符串。後面的bcawk命令能夠用於進行小數(浮點數)運算,但通常用到的較少。

僅支持整數的運算

echo $((數學運算表達式))
# 形式一
[root@mico scripts]# echo $((1 + 1))
2
[root@mico scripts]# echo $((2*7-3/6+5))
19
# 形式二
[root@mico scripts]# ((mico=2*8))
[root@mico scripts]# echo $mico
16
# 形式三
[root@mico scripts]# znix=$((2*7-3/6+5))
[root@mico scripts]# echo $znix
19
延伸產物(重要)
  • i++ 自增1
  • i-- 自減1
  • ++i
  • --i

示例:

[root@mico scripts]# i=1
[root@mico scripts]# echo $((i++))
1
[root@mico scripts]# echo $((i++))
2
[root@mico scripts]# echo $((i--))
3
[root@mico scripts]# echo $((i--))
2
[root@mico scripts]# echo $((i--))
1
[root@mico scripts]# echo $((++i))
1
[root@mico scripts]# echo $((++i))
2
[root@mico scripts]# echo $((++i))
3
[root@mico scripts]# echo $((--i))
2
[root@mico scripts]# echo $((--i))
1
[root@mico scripts]# echo $((--i))
0

記憶方法:++,--
變量a在前,表達式的值爲a,而後a自增或自減,變量a在符號後,表達式值自增或自減,而後a值自增或自減。

let命令

[root@mico scripts]# i=1
[root@mico scripts]# i=i+1
[root@mico scripts]# echo $i
i+1

[root@mico scripts]# i=1
[root@mico scripts]# let i=i+1
[root@mico scripts]# echo $i
2

expr 命令

  • 整數計算
  • 判斷擴展名
  • 判斷輸入是否爲整數,非整數返回值爲2
  • 計算變量的長度
示例
[root@mico scripts]# expr 1+1
1+1
[root@mico scripts]# expr 1 + 1
2
[root@mico scripts]# expr 1 * 1
expr: 語法錯誤
[root@mico scripts]# expr 1 \* 1
1
非整數返回值爲2 示例:
[root@mico scripts]# expr 1 + 1 
2
[root@mico scripts]# echo $?
0
[root@mico scripts]# expr -1 + 1 
0
[root@mico scripts]# echo $?
1
[root@mico scripts]# expr a + 1 
expr: 非整數參數
[root@mico scripts]# echo $?
2
$[]運算符
[root@mico scripts]# echo $[1+2]
3
[root@mico scripts]# echo $[1-2]
-1
[root@mico scripts]# echo $[1*2]
2
[root@mico scripts]# echo $[1/2]
0

typeset 命令進行運算

[root@mico scripts]# typeset -i A=2017 B=2018
[root@mico scripts]# A=A+B
[root@mico scripts]# echo $A
4035

能夠進行小數運算的命令

bc 命令

# 安裝 bc  依賴於base源
[root@mico scripts]# yum -y install bc
  交互模式測試bc命令
[root@mico scripts]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. 
1+1
2
[root@mico scripts]# echo 1+1.1|bc
2.1

免交互模式測試bc命令

[root@mico scripts]# echo 'scale=6;1/3'|bc
.333333
python 命令
[root@mico scripts]#  file `which yum `
/usr/bin/yum: Python script, ASCII text executable
[root@mico scripts]# python 
>>> import os
>>> os.system('df -h')
>>> 1+1.1
2.1
>>>exit()

awk 命令

[root@mico ~]# echo "7.7 3.8"|awk '{print ($1-$2)}'
3.9
[root@mico ~]# echo "358 113"|awk '{print ($1-3)/$2}'
3.14159
[root@mico ~]# echo "3 9"|awk '{print ($1+3)*$2}'
54
[root@backup scripts]# awk BEGIN'{print 1.2+3.3}'
4.5

運算相關練習題

【練習題】實現一個加減乘除等功能的計算器

實現腳本:

[root@mico scripts]# cat calculator.sh 
#!/bin/bash

read -p "請輸入第一個整數:" a
read -p "請輸入第二個整數:" b


echo $a + $b =$(($a+$b))
echo $a - $b =$(($a-$b))
echo $a \* $b =$(($a*$b))
echo $a / $b =$(($a/$b))
         腳本執行過程:
[root@mico scripts]# sh calculator.sh 
請輸入第一個整數:12
請輸入第二個整數:12
12 + 12 =24
12 - 12 =0
12 * 12 =144
12 / 12 =1
精簡方法
[root@mico scripts]# vim calculator2.sh 
#!/bin/bash

echo $(($1))
         腳本執行過程:
[root@mico scripts]# sh calculator2.sh  1+1
2
[root@mico scripts]# sh calculator.sh  1*9
9

【練習題】打印結果1+2+3+4+5+6+7+8+9+10=55

腳本內容

[root@mico scripts]# vim count.sh
#!/bin/bash

Num=`seq -s + 1 10`
echo  $Num=$(($Num))

腳本執行結果

[root@mico scripts]# sh  count.sh
1+2+3+4+5+6+7+8+9+10=55

補充說明

shell腳本中批量註釋的方法
<<'EOF'

文件內容
EOF 或使用 exit 能夠註釋其以後的全部內容(相似註釋,實質爲不執行後面的內容)

相關文章
相關標籤/搜索