先介紹一下什麼是shell吧:
殼層在計算機科學中,是指“提供用戶使用界面”的軟件,通常指的是命令行界面的解析器。一般來說,這
個詞是指操作系統中,提供訪問內核所提供之服務的程序。Shell也用於泛指所有爲用戶提供操作界面的
程序,也就是程序和用戶交互的層面。因此與之相對的是程序內核,內核不提供和用戶的交互功能。 不
過這個詞也拿來指應用軟件,或是任何在特定組件外圍的軟件,例如瀏覽器或電子郵件軟件是HTML排版
引擎的shell。Shell這個詞是來自於操作系統與用戶界面的外層界面。 通常將殼層分爲兩類:命令行與圖
形界面。命令行殼層提供一個命令行界面;而圖形殼層提供一個圖形用戶界面。
bash:據我老師說的,第一次能把Hello world程序成功運行出來,你將會在學習的路上會順利一點,嘿嘿,有點小迷信了,那麼就先從Hello world程序開始吧。
用vim編輯器編輯hello文件:
#!/bin/bash
# This is a simple example
echp Hello world
這時候該有同學問#!是什麼啊,有什麼用,/bin/bash又是什麼,
首先,#! 是說明 hello 這個文件的類型的,有點類似於 Windows 系統下用不同文件後綴來表示不同文件類型的意思(但不相同)。Linux 系統根據 “#!” 及該字串後面的信息確定該文件的類型。
其次,在 BASH 中 第一行的 “#!” 及後面的 “/bin/bash” 就表明該文件是一個 BASH 程序,需要由 /bin 目錄下的 bash 程序來解釋執行。BASH 這個程序一般是存放在 /bin 目錄下,如果你的 Linux 系統比較特別,bash 也有可能被存放在 /sbin 、/usr/local/bin 、/usr/bin 、/usr/sbin 或 /usr/local/sbin 這樣的目錄下。
如何執行該程序呢?有兩種方法:一種是顯式制定 BASH 去執行:
$ bash hello 或
$ sh hello (這裏 sh 是指向 bash 的一個鏈接,“lrwxrwxrwx 1 root root 4 Aug 20 05:41 /bin/sh -> bash”)
或者可以先將 hello 文件改爲可以執行的文件,然後直接運行它,此時由於 hello 文件第一行的 “#! /bin/bash” 的作用,系統會自動用/bin/bash 程序去解釋執行 hello 文件的:
$ chmod u+x hello
$ ./hello
此處沒有直接 “$ hello”是因爲當前目錄不是當前用戶可執行文件的默認目錄,而將當前目錄“.”設爲默認目錄是一個不安全的設置。
需要注意的是,BASH 程序被執行後,實際上 Linux 系統是另外開設了一個進程來運行的。
bash特性之命令別名和命令引用
alias
alias ALIAS=COMMAND
示例:
[root@stu31 ~]# alias ls='ls -la'
[root@stu31 ~]# ls /tmp/
total 80
drwxrwxrwt. 5 root root 4096 Aug 3 12:19 .
dr-xr-xr-x. 27 root root 4096 Aug 3 11:12 ..
drwxr-xr-x 2 root root 4096 Jul 28 14:58 dangerous
-rw------- 1 root root 0 Jul 28 10:04 grub-install.img.504t6u
-rw------- 1 root root 401 Jul 28 10:04 grub-install.log.fPXD9g
drwxrwxrwt 2 root root 4096 Aug 3 11:12 .ICE-unix
-rwx------. 1 root root 1118 Jul 28 09:11 ks-script-0C1VlZ
-rwxr-xr-x. 1 root root 67 Jul 28 09:11 ks-script-0C1VlZ.log
drwxr-xr-x 2 root root 53248 Jul 28 14:48 test
-rw-------. 1 root root 0 Jul 28 08:47 yum.log
別名與命令同名時,要使用絕對路徑,\COMMAND生效範圍:命令行定義的別名,其生效範圍爲當前會話;
unalias [ALIAS]
-a: 撤消所有別名
示例:
[root@stu31 ~]# unalias ls
[root@stu31 ~]# ls /tmp/
dangerous grub-install.log.fPXD9g ks-script-0C1VlZ.logyum.log
grub-install.img.504t6u ks-script-0C1VlZ test
bash支持的引用:
''
""
``:引用一個命令的執行結果
示例:
1alias ls='ls --color=auto' #輸出顯示爲彩色
2[root@stu31 /]# cd `who am i`
[root@stu31 ~]#
bash特性之文件名通配(globbing):
?:匹配任意字符
*:匹配任意長度任意字符
例:*a *b a*b *a*b*
[]:匹配指定範圍內的任意單字符
例:[a-z];[0-9];[a-z0-9]
[^]:匹配指定範圍意外的任意單字符
例:[^0-9]
字符集合:
[:space:] : 所有空白字符
[:punct:] : 所有標點符號
[:lower:] :所有小寫字母
[:upper:] :所有大寫字母
[:digit:] :所有數字
[:alnum:] :所有大小寫字母和數字
[:alpha:] :所有字母
示例:顯示/etc目錄下,以非字母開頭,文件或目錄;
# ls -d /etc/[^[:alpha:]]*
bash之快捷鍵:
Ctrl+a: 跳轉至命令行首
Ctrl+e: 跳轉至命令行尾
Ctrl+u: 刪除命令行首至當前光標所在處之前的所有內容
Ctrl+k: 刪除當前光標所在處至命令行尾的所有內容
Ctrl+l: 清屏
Ctrl+c: 中止或取消
Ctrl+z: 把當命令送至後臺
bash之bash變量:
bash變量類別:
本地變量:只對當前shell進程有效的變量;對其它shell進程無效,包當前 shell進程的子進程;
VAR_NAME=VALUE
變量賦值:向變量的存儲空間保存數據
示例:
[root@stu31 ~]# a=1
[root@stu31 ~]# b=2
[root@stu31 ~]# echo $a
1
[root@stu31 ~]# echo $b
2
變量引用:${VAR_NAME}
"":弱引用,裏面的變量會被替換;
'':強引用,裏面的所有字符都是字面量,直接輸出;
環境變量:對當前shell進程及其子shell有效,對其它的shell進程無效;
定義:export VAR_NAME=VALUE
導出:export VAR_NAME
用戶可自義環境變量
bash有許多內置的環境變量
撤消變量:unset VAR_NAME
只讀變量:readonly VAR_NAME
局部變量:
對shell腳本中某代碼片斷有效;通常用於函數本地;
local VAR_NAME=VALUE
位置變量:
$1, $2, ..., ${10}
查看當前shell進程中的所有變量:set
查看當前shell進程中的所有環境變量:export, printenv, env
變量命名:
1、不能使用程序中的關鍵字(保留字);
比如:if, case, for
2、只能使用數字、字母和下劃線,且不能以數字開頭;
3、要見名知義
File
變量類型:
name=Jerry
1、存儲機制
2、存儲空間
3、參與的運算方式
變量類型:
數值型:
精確數值:整數
近似數值:浮點型
單精度浮點
雙精度浮點
字符型:
char
string
布爾型:
true, false
類型轉換:
顯式轉換
隱式轉換
bash是弱類型的語言:一切皆字符
bash之bash的配置文件:
profile類:爲交互式登錄的用戶提供配置
全局:
/etc/profile
/etc/profile.d/*.sh
用戶:
~/.bash_profile
功用:
1、設定環境變量
2、運行命令或腳本
bashrc類:爲非交互式的用戶提供配置
全局:
/etc/bashrc
用戶:
~/.bashrc
功用:
1、設定本地變量
2、定義命令別名
登錄類型:
交互式:
直接通過終端輸入賬號和密碼登錄;
使用su -l USERNAME 或 su - USERNAME;
非交互式:
su USERNAME
圖形界面下打開的終端
執行腳本
通過編輯配置文件修改的配置生效?
1、退出並重新登錄;
2、讓bash重讀此配置文件;
. FILE
source FILE
交互登錄的用戶:
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
非交互登錄的用戶:
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
bash之bash編程:
特殊變量:
$#,$*: 傳遞給腳本參數的個數
$@:引用傳遞給腳本的所有參數
$?:狀態返回值
bash的循環語句:
for
while
until
for語句格式:
for 變量 in 列表 ;do
執行的命令
done
(退出條件:遍歷結束)
for的第二種使用格式 :
for ((初始條件;測試條件;修改表達式)); do
循環體
done
例:for file in `ls`;do echo $file;done
創建十個文件夾file1-file10
#!/bin/bash
for fileName in {1..10};do
touch file$(fileName)
done
計算100以內所有正整數之和
#!/bin/bash
#
declare -i sum=0
for ((counter=1;$counter <= 100; counter++)); do
let sum+=$counter
done
echo $sum
while語句格式:
while 條件; (注:只要特定條件爲真,”while” 語句就會執行)
do
語句
done
示例:
#!/bin/bash
COUNTER=0
while [ $COUNTER -lt 10 ]; do
echo The counter is $COUNTER
let COUNTER=COUNTER+1
done
until語句格式:
until 條件; (注:只要特定條件爲假,”while” 語句就會執行)
do
語句
done
示例:
#!/bin/bash
myvar=1
until [ $myvar -gt 10 ]do
echo $myvar
myvar=$(( $myvar + 1 ))
done
生成列表的方式:
1、手動給個列表:
for i in 1 2 3 4 5;
2、數值列表:
{start..end}
`seq [start [increment]] end`
3、$*, $@
4 、命令生成列表
示例:
顯示/etc/passwd文件中位於文件的第偶數行的用戶名;並顯示共有多少個這樣的用戶;
#!/bin/bash
#
totalUsers=`wc -l /etc/passwd | cut -d' ' -f1`
for i in `seq 2 2 $totalUsers`; do
userName=`head -n $i /etc/passwd | tail -1 | cut -d: -f1`
echo $userName >> /tmp/passwd.tmp
echo $userName
done
users=`wc -l /tmp/passwd.tmp | cut -d' ' -f1`
echo "Total users: $users."
bash之bash如何實現算術運算:
變量:弱類型
如何定義整型變量:
let VAR_NAME=INTEGER_VALUE
例如:let a=1
declare -i VAR_NAME=INTEGER_VALUE
例如:declare -i a=3
注意:即使沒有定義爲整型變量,字符型的數字依然可以參與算術運算;bash會執行變量類型的隱式類型轉換;
實現算術運算的方式:
let VAR_NAME=ARITHMATIC_EXPRESSION
VAR_NAME=$[ARITHMATIC_EXRESSION]
VAR_NAME=$((EXPRESSION))
VAR_NAME=$(expr $num1 + $num2)
算術運算符:
+
-
*
/
%:取模,取餘數
5%2=1,
**: 2**3 (這是次方運算,2的3次方)
示例:
分別計算100以內所有偶數之和和奇數之和;
#!/bin/bash
#
declare -i evensum=0
declare -i oddsum=0
for i in `seq 1 2 100`; do
oddsum=$[$oddsum+$i]
done
for j in `seq 2 2 100`; do
evensum=$[$evensum+$j]
done
echo "evensum: $evensum, oddsum: $oddsum."
寫一個腳本
1、腳本可以接受一個以上的文件路徑作爲參數;
2、顯示每個文件所擁有的行數;
3、顯示本次共對多少個文件執行了行數統計;
4、顯示所有文件的總行數;
#!/bin/bash
#
declare -i totalLines=0
declare -i noFiles=0
for file in $*; do
curFileLines=`wc -l $file | cut -d' ' -f1`
echo "$file has $curFileLines."
let noFiles++
let totalLines+=$curFileLines
done
echo "Total Files: $noFiles."
echo "Total Lines: $totalLines."
bash弱類型:
變量=值
任何無需事先聲明,可直接使用
值默認都是字符型
a=abc, b=3
a=3
賦值:
a=4
增強型賦值:
+=, -=, *=, /=, %=
a=$[$a+1] 相當於 let a+=1
自加:var++, var--, ++var, --var
export PATH=$PATH:/usr/local/apache/bin
unset: 撤消
算術運算:bash會對數字執行隱式的類型轉換
let VAR_NAME=Integer_Value
declare -i Var_Name=Integer_Value
操作符:
+, -, *, /, %, **
雙目運算符:需要至少兩個操作數
bash的算術運算的方式:
let Var_Name=EXPRESSION
$[EXPRESSION]
$((EXPRESSION))
命令:expr ARG1 OP ARG2
例:計算100內的所有正整數的和
#!/bin/bash
declare -i sum=0
for i in {1..100}; do
let sum+=$i
done
echo $sum
邏輯運算:
布爾運算:真,假
與、或、非、異或
與運算:
真,假:
真 && 真 = 真
真 && 假 = 假
假 && 真 = 假
假 && 假 = 假
或運算:
真,假
真 || 真 = 真
真 || 假 = 真
假 || 真 = 真
假 || 假 = 假
非運算:
真,假
!真=假
!假=真
命令都有其狀態返回值:
成功:0,真
失敗:1-255, 假
bash條件測試:
命令執行成功與否即爲條件測試
test EXPR
[ EXPR ]
` EXPR `
比較運算:
>, <, >=, <=, ==, !=
測試類型:根據比較時的操作數的類型
整型測試:整數比較
字符測試:字符串比較
文件測試:判斷文件的存在性及屬性等
(注意:比較運算通常只在同一種類型間進行)
整型測試:
-gt: 大於
-lt: 小於
-ge: 大於等於
-le: 小於等於
-eq: 等於
-ne: 不等於
字符串測試:
雙目
>: [[ "$string1" > "$string2" ]]
<:
>=
<=
==
!=
單目:
-n String: 是否不空,不空則爲真,空則爲假
-z String: 是否爲空,空則爲真,不空則假
bash之bash選擇:
if: 三種使用格式
單分支的if語句:
if 測試條件; then
選擇分支
fi
表示條件測試狀態返回值爲值,則執行選擇分支;
雙分支的if語句:
if 測試條件; then
選擇分支1
else
選擇分支2
fi
兩個分支僅執行其中之一。
多分支的if語句:
if 條件1; then
分支1
elif 條件2; then
分支2
elif 條件3; then
分支3
...
else
分支n
fi
例:1寫一個腳本,接受一個參數,這個參數是用戶名;如果此用戶存在,則顯示其ID號;
#!/bin/bash
if ! id $username &> /dev/null; then
useradd $username
fi
2通過命令行給定一個文件路徑,而後判斷:
如果此文件中存在空白行,則顯示其空白行的總數;
否則,則顯示無空白行;
#!/bin/bash
if grep "^[[:space]]*$" $1 &> /dev/null; then
echo "$1 has $(grep "^[[:space]]*$" $1 | wc -l) blank lines."
else
echo "No blank lines"
fi
3傳遞一個用戶名給腳本:
如果此用戶的id號爲0,則顯示說這是管理員
如果此用戶的id號大於等於500,則顯示說這是普通用戶
否則,則說這是系統用戶;
#!/bin/bash
if [ $# -lt 1 ]; then
echo "Usage: `basename $0` username"
exit 1
fi
if ! id -u $1 &> /dev/null; then
echo "Usage: `basename $0` username"
echo "No this user $1."
exit 2
fi
if [ $(id -u $1) -eq 0 ]; then
echo "Admin"
elif [ $(id -u $1) -ge 500 ]; then
echo "Common user."
else
echo "System user."
fi
bash字串測試中的模式匹配:
[[ "$var" =~ PATTERN ]]
例:讓用戶給定一個用戶名,判斷其是否擁有可登錄shell;
#!/bin/bash
#
read -p "Plz input a username: " userName
userInfo=`grep "^$userName\>" /etc/passwd`
if [[ "$userInfo" =~ /bin/.*sh$ ]]; then
echo "can login"
else
echo "cannot login"
fi
bash之case語句:
一般,case語句和if一起使用,但是隻要你面臨可能採取的一系列不同的動作時,你可能迷惑,要處理複雜條件時,你可以考慮一下case語句
case表達式:
case
EXPRESSION
in
CASE1
) COMMAND-LIST;;
CASE2
) COMMAND-LIST;;
...
COMMAND-LIST;; CASEN
)
esac
每個分支是一個符合pattern的表達式,在COMMAND-LIST中首先符合的命令就執行該條,沒個case語句以esac結束
例:
#!/bin/bash
# 1.) Open file 2.) Display file 3.) Edit file 4.) Delete file
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "---------------------------------"
echo "List of item to operate file -"
echo "---------------------------------"
echo "1). Open a file -"
echo "2). Display a file -"
echo "3). Edit a file -"
echo "4). Delete a file -"
echo "---------------------------------"
read select
case $select in
1)
echo "do open file operation"
2)
echo "do display a file operation"
3)
echo "do edit a file operation"
4)
echo "do delete a file operation"
*)
echo "There is nothing to do!"
exit 1
esac
bash之數組:
1,聲明一個數組
declare -i array
2,數組賦值
(1) array=(a1 a2 a3 ... aN)
(2)array=([0]=a1 [2]=a2 [3]=a3 ... [n]=aN)
(3)array[0]=a1 array[1]=a2 array[2]=a3 ... array[n]=aN
3,數組複製:
要使用${ARRAY[@]}
$@: 每個參數是一個獨立的串
$*: 所有參數是一個串
4,引用數組
echo ${array[n]}
5,數組的訪問:
用索引訪問:
ARRAY[index]
6,從數組中挑選某元素:
${ARRAY[@]:offset:number}
切片:
offset: 偏移的元素個數
number: 取出的元素的個數
${ARRAY[@]:offset}:取出偏移量後的所有元素
${ARRAY[@]}: 取出所有元素
7,從數組中刪除元素:
unset ARRAY[index]
例:將字串裏的字母逐個放入數組中並輸出
#!/bin/bah
chars='qazwsx'
for((i=0;i<=6;i++));do
array[$i]=${chars:$i:1} (表示從chars字符串的 $i 位置開始,獲取 1 個字符)
echo ${array$[$i]}
done
複製一個數組中下標爲偶數的元素至一個新數組中
#!/bin/bash
declare -a mylogs
logs=(/var/log/*.log)
echo ${logs[@]}
for i in `seq 0 ${#logs[@]}`; do
if [ $[$i%2] -eq 0 ];then
index=${#mylogs[@]}
mylogs[$index]=${logs[$i]}
fi
done
echo ${mylogs[@]}