概述:本章主要介紹bash編程中的函數和數組以及字符串處理和程序包管理工具等,來幫助小伙伴們更進一步的了解bash編程的內容和軟件的安裝、更新、卸載、查詢等操作。
一、函數介紹
函數function是由若干條shell命令組成的語句塊,實現代碼重用和模塊化編程。
它與shell程序形式上是相似的,不同的是它不是一個單獨的進程,不能獨立運行,而是shell程序的一部分。
函數和shell程序比較相似,區別在于:
Shell程序在子Shell中運行,而Shell函數在當前Shell中運行。因此在當前Shell中,函數可以對shell中變量進行修改
函數:function
過程式編程:代碼重用
模塊化編程
結構化編程
把一段獨立功能的代碼當作一個整體,并為之一個名字;命名的代碼段,此即為函數;
注意:定義函數的代碼段不會自動執行,在調用時執行;所謂調用函數,在代碼中給定函數名即可;函數名出現的任何位置,在代碼執行時,都會被自動替換為函數代碼;
語法一:
function f_name {
…函數體…
}
語法二:
function f_name () {
…函數體…
}
? 語法三:
f_name() {
…函數體…
}
推薦使用第三種語法,簡潔
函數使用
? 函數的定義和使用:
可在交互式環境下定義函數
可將函數放在腳本文件中作為它的一部分
可放在只包含函數的單獨文件中
? 調用:函數只有被調用才會執行;
調用:給定函數名
函數名出現的地方,會被自動替換為函數代碼
? 函數的生命周期:每次被調用時創建,返回時終止
函數返回值
? 函數有兩種返回值:
? 函數的執行結果返回值:
(1) 使用echo或printf命令進行輸出
(2) 函數體中調用命令的輸出結果
函數的退出狀態碼:
(1) 默認取決于函數中執行的最后一條命令的退出狀態碼
(2) 自定義退出狀態碼, 其格式為:
return 從函數中返回,用最后狀態命令決定返回值
return 0 無錯誤返回。
return 1-255 有錯誤返回
遇到return函數生命周期就結束了
示例:給定一個用戶名,去的用戶名的第號和默認shell;
#!/bin/bash #userinfo(){ if id "$username" &> /dev/null;then grep "^$username\>" /etc/passwd |cut -d: -f3,7 else echo "No such user." fi } username=$1 userinfo username=$2 userinfo
#!/bin/bash # #chkconfig: - 50 50 #description:test service script prog=$(bashname $0) lockfile=/var/lock/subsys/$prog start() {} if [ -f $lockfile ];then echo "$prog is running yet." else touch $lockfile [ $? -eq 0 ] && echo "start $prog finshed." fi } stop(){ if [ -f $lockfile ];then rm -f $lockfile [ $? -eq 0 ] && echo "stop $prog finished." else echo "$prog is not running" fi } restart() { if [ -f $lockfile ];then rm -f $lockfile touch $lockfile echo "restart $prog finshed." else touch -f $lockfile echo "start $prog finshed." fi } status() { if [ -f $lockfile ];then echo "$prog is running." else echo "$prog is stoped." fi } usage() { echo "USage: $prog {start|stop|restart|status}" } case $1 in start) start ;; stop) stop ;; restatrt) stop start;; status) status;; *) usage exit 1 ;; esac
注意:
使函數文件可以將經常使用的函數存入函數文件,然后將函數文件載入shell。
文件名可任意選取,但最好與相關任務有某種聯 系。例如: functions.main
一旦函數文件載入shell,就可以在命令行或腳本中調用函數??梢允褂胹et命令查看所有定義的函數,其輸出列表包括已經載入shell的所有函數。
若要改動函數,首先用unset命令從shell中刪除函數。改動完畢后,再重新載入此文件。
創建函數文件
? 函數文件示例:
cat functions.main #!/bin/bash #functions.main findit() { if [ $# -lt 1 ] ; then echo "Usage:findit file" return 1 fi find / -name $1 –print }
載入函數
? 函數文件已創建好后,要將它載入shell
? 定位函數文件并載入shell的格式:
. filename 或 source filename
? 注意:此即<點> <空格> <文件名>
這里的文件名要帶正確路徑
? 示例:上例中的函數,可使用如下命令:
. functions.main
檢查載入函數
? 使用set命令檢查函數是否已載入。 set命令將在shell中顯示
所有的載入函數。
? 示例:
#set findit=( ) { if [ $# -lt 1 ]; then echo "usage :findit file"; return 1 fi find / -name $1 -print }
執行shell函數
? 要執行函數,簡單地鍵入函數名即可:
? 示例:
findit groups /usr/bin/groups /usr/local/backups/groups.bak
刪除shell函數
? 現在對函數做一些改動。首先刪除函數,使其對shell不可用
。使用unset命令完成此功能.
? 命令格式為:
? unset function_name
? 實例:
$unset findit
再鍵入set命令,函數將不再顯示
函數參數
? 函數可以接受參數:
傳遞參數給函數:調用函數時,在函數名后面以空白分隔
給定參數列表即可;例如“ testfunc arg1 arg2 …”
在函數體中當中,可使用$1, $2, …調用這些參數;還
可以使用$@, $*, $#等特殊變量
示例:添加10個用戶,添加用戶的功能使用函數實現,用戶名作為參數傳遞給函數。
#!/bin/bash # addusers() { if id $1 &>/dev/null;then return 5 else useradd $1 retval=$? return=$retval fi } for i in {1..10};do addusers ${1}${i} retval=$? if [ $retval -eq 0 ];then echo "Add user ${1}${i} finished." elif [ $retval -eq 5 ];then echo "User ${1}${i} exists." else echo "Unkown Error." fi done
函數變量
變量作用域:
環境變量:當前shell和子shell有效
本地變量:只在當前shell進程有效,為執行腳本會啟動
專用子shell進程;因此,本地變量的作用范圍是當前shell腳本
程序文件,包括腳本中的函數。
局部變量:函數的生命周期;函數結束時變量被自動銷毀
? 注意:如果函數中有局部變量,如果其名稱同本地變量,使
用局部變量。
在函數中定義局部變量的方法
local NAME=VALUE
示例:
#!/bin/bash # name=tom setname() { local name=jerry echo "Function:$name" } setname echo "Shell:$name"
函數遞歸實例
函數遞歸:
函數直接或間接調用自身
注意遞歸層數
遞歸實例:
階乘是基斯頓·卡曼于1808年發明的運算符號,是數學術語
一個正整數的階乘(factorial)是所有小于及等于該數的正整數的積,并且有0的階乘為1。自然數n的階乘寫作n!。
n!=1×2×3×…×n。
階乘亦可以遞歸方式定義: 0!=1, n!=(n-1)!×n。
n!=n(n-1)(n-2)…1
n(n-1)! = n(n-1)(n-2)!
示例1:求n的階乘
#!/bin/bash # fact() { if [ $1 -eq 0 -o $1 -eq 1 ];then echo 1 else echo $[$1*$(face$[$1-1])] fi } fact $1
示例2:求斐波那契數列各代的值
#!/bin/bash # fab() { if [ $1 -eq 1 ];then echo -n "1 " elif [ $1 -eq 2 ];then echo -n "1" else echo "$[$(fab$[$1-1])+$(fab$[$1-2])] " fi } for i in $(seq 1 $1);do fab $i done echo
數組
? 變量:存儲單個元素的內存空間
數組:存儲多個元素的連續的內存空間,相當于多個變量的集合。
? 數組名和索引
數組名:整個數組只有一個名字;
索引:編號從0開始,屬于數值索引
數組名[索引]
${ARRAY_NAME[INDEX]}
注意:bash4.0版本之后開始支持索引可支持使用自定義的格式(也可以是字符),而不僅是數值格式,即為關聯索引,
bash的數組支持稀疏格式(索引不連續)
定義數組
? 聲明數組:
declare -a ARRAY_NAME:聲明索引數組
declare -A ARRAY_NAME:聲明關聯數組
關聯數組(先聲明再使用)
數組元素的賦值:
(1) 一次只賦值一個元素;
ARRAY_NAME[INDEX]=VALUE
例如:
weekdays[0]="Sunday" weekdays[4]="Thursday"
示例:
menu[0]=hsr
menu[1]=mckr
menu[2]=bjky
echo ${menu[*]}
(2) 一次賦值全部元素:
ARRAY_NAME=("VAL1" "VAL2" "VAL3" …)
[root@localhost bin]# number=(1 2 5 6 7 9 10) [root@localhost bin]# echo ${number[*]} [root@localhost bin]# number2=({1..9}) [root@localhost bin]# echo ${number2[*]} 1 2 3 4 5 6 7 8 9
[root@localhost bin]# files=(/tmp/*) root@localhost bin]# echo ${files[*]} /tmp/1223 /tmp/123 /tmp/a /tmp/b /tmp/bb /tmp/file1 /tmp/hogsuspend /tmp/per5.sh /tmp/ssh-0gAHISs2wV2R /tmp/systemd-private-b1280e3fddc544dc9e3b2e371fce366f-colord.service-NshluI /tmp/systemd-private-b1280e3fddc544dc9e3b2e371fce366f-cups.service-fzhP58 /tmp/systemd-private-b1280e3fddc544dc9e3b2e371fce366f-rtkit-daemon.service-h7vLWl /tmp/systemd-private-b1280e3fddc544dc9e3b2e371fce366f-vmtoolsd.service-h4soY3 /tmp/tracker-extract-files.0 /tmp/VMwareDnD /tmp/vmware-root
[root@localhost bin]# files=({1,2}.) [root@localhost bin]# echo ${files[*]} 1. 2.
(3) 只賦值特定元素:
ARRAY_NAME=([0]="VAL1" [3]="VAL2" …)
num=([0]=100 [2]=20 [10]=1000)
(4) 交互式數組值對賦值
read -a ARRAY
[root@localhost bin]# read -a num 1 3 5 7 78 96 1 3 4 8 [root@localhost bin]# echo ${num[*]} 1 3 5 7 78 96 1 3 4 8
引用數組
? 引用數組元素: ${ARRAY_NAME[INDEX]}
注意:省略[INDEX]表示引用下標為0的元素
數組的長度(數組中元素的個數):(變量也可以應用)
${#ARRAY_NAME[*]}
${#ARRAY_NAME[@]}
示例:生成10個隨機數保存于數組中,并找出其最大值和最小值
#!/bin/bash declare -a rand declare -i max=0 for i in {0..9}; do rand[$i]=$RANDOM echo ${rand[$i]} [ ${rand[$i]} -gt $max ] && max=${rand[$i]} done echo "Max: $max"
練習
? 編寫腳本,定義一個數組,數組中的元素是/var/log目錄下所有以.log結尾的文件;要統計其下標為偶數的文件中的行數之和
#!/bin/bash # declare -a files files=(/var/log/*.log) declare -i lines=0 for i in $(seq 0 $[${#files[*]}-1]); do if [ $[$i%2] -eq 0 ];then let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1) fi done echo "Lines: $lines."
數組數據處理
? 引用數組中的元素:
所有元素: ${ARRAY[@]}, ${ARRAY[*]}
數組切片: ${ARRAY[@]:offset:number}
offset: 要跳過的元素個數
number: 要取出的元素個數
取偏移量之后的所有元素
${ARRAY[@]:offset}
? 向數組中追加元素:
ARRAY[${#ARRAY[*]}]
? 刪除數組中的某元素:導致稀疏格式
unset ARRAY[INDEX]
? 關聯數組:
declare -A ARRAY_NAME
ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2‘…)
字符串處理
? bash的字符串處理工具:
? 字符串切片:
${#var}:返回字符串變量var的長度
${var:offset}:返回字符串變量var中從第offset個字符后(不包括第offset個字符)的字符開始,到最后的部分,offset的取值在0 到 ${#var}-1 之間(bash4.2后,充許為負值)
${var:offset:number}:返回字符串變量var中從第offset個字符后(不包括第offset個字符)的字符開始,長度為number的部分
${var: -lengh}:取字符串的最右側幾個字符:
注意:冒號后必須有一空白字符
基于模式取子串:
${var#*word}:其中word可以是指定的任意字符
功能:自左而右,查找var變量所存儲的字符串中,第一次出現的word, 刪除字符串開頭至第一次出現word字符之間的所有字符
${var##*word}:同上,不同的是,刪除的是字符串開頭至最后一次由word指定的字符之間的所有內容
file="/var/log/messages"
${file##*/}: messages
${var%word*}:其中word可以是指定的任意字符;
功能:自右而左,查找var變量所存儲的字符串中,第一次出現的word, 刪除字符串最后一個字符向左至第一次出現word字符之間的所有字符;
file="/var/log/messages"
${file%/*}: /var/log
? ${var%%word*}:同上,只不過刪除字符串最右側的字符向左至最后一次出現word字符之間的所有字符;
? 示例: url=http://www.magedu.com:80
${url##*:} 80
${url%%:*} http
查找替換:
${var/pattern/substi}:查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substi替換之
${var//pattern/substi}: 查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substi替換之
${var/#pattern/substi}:查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substi替換之
${var/%pattern/substi}:查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substi替換之
查找并刪除:
${var/pattern}:查找var所表示的字符串中,刪除第一次被pattern所匹配到的字符串
${var//pattern}:查找var所表示的字符串中,刪除所有被pattern所匹配到的字符串
${var/#pattern}:查找var所表示的字符串中,刪除行首被pattern所匹配到的字符串
${var/%pattern}:查找var所表示的字符串中,刪除行尾被pattern所匹配到的字符串
字符大小寫轉換:
${var^^}:把var中的所有小寫字母轉換為大寫
${var,,}:把var中的所有大寫字母轉換為小寫
變量賦值
? ${var:-value}:如果var為空或未設置,那么返回value;否則,則返回var的值
? ${var:+value}:如果var不空,則返回value
? ${var:=value}:如果var為空或未設置,那么返回value,并將value賦值給var;否則,則返回var的值
? ${var:?error_info}:如果var為空或未設置,那么返回error_info;否則,則返回var的值為腳本程序使用配置文件,實現變量賦值
(1) 定義文本文件,每行定義“ name=value”
(2) 在腳本中source此文件即可
高級變量用法-有類型變量
? Shell變量一般是無類型的,但是bash Shell提供了declare和
typeset兩個命令用于指定變量的類型,兩個命令是完全等價
的
? declare [選項] 變量名
-r 將變量設置為只讀屬性
-i 將變量定義為整型數
-a 將變量定義為數組
-f 顯示此腳本前定義過的所有函數名及其內容
-F 僅顯示此腳本前定義過的所有函數名
-x 將變量聲明為環境變量
-l 將變量值轉為小寫字母
-u 將變量值轉為大寫字母
間接變量引用
? 如果第一個變量的值是第二個變量的名字,從第一個變量引
用第二個變量的值就稱為間接變量引用
? variable1=variable2
? variable2=value
? variable1的值是variable2,而variable2又是變量名,
variable2的值為value,間接變量引用是指通過variable1獲
得變量值value的行為
間接變量引用
? bash Shell提供了兩種格式實現間接變量引用
eval tempvar=\$$variable1
tempvar=${!variable1}
示例:
[root@server ~]# N=NAME [root@server ~]# NAME=wangxiaochun [root@server ~]# N1=${!N} [root@server ~]# echo $N1 wangxiaochun [root@server ~]# eval N2=\$$N [root@server ~]# echo $N2 wangxiaochun
eval命令
? eval命令將會首先掃描命令行進行所有的置換,然后再執
行該命令。該命令適用于那些一次掃描無法實現其功能的
變量。該命令對變量進行兩次掃描。
示例:
[root@server ~]# V1=pwd [root@server ~]# echo $V1 pwd [root@server ~]# eval $V1 /root
創建臨時文件
mktemp命令:創建的臨時文件可避免沖突
mktemp [OPTION]… [TEMPLATE]
TEMPLATE: filename.XXX
X至少要出現三個
OPTION:
-d: 創建臨時目錄
-p DIR或–tmpdir=/DIR:指明臨時文件所存放的目錄位置
實例:
#mktemp /tmp/test.XXX #tmpdir=`mktemp –d /tmp/testdir.XXX` #mktemp --tmpdir=/testdir test.XXXXXX
安裝復制文件
install命令:默認會給文件執行權限;用于源碼安裝
install [OPTION]… [-T] SOURCE DEST 單文件
install [OPTION]… SOURCE… DIRECTORY
install [OPTION]… -t DIRECTORY SOURCE…
install [OPTION]… -d DIRECTORY…創建空目錄
選項:
-m MODE,默認755
-o OWNER
-g GROUP
-d 創建目錄
示例:
install -m 700 -o wang -g admins file1 file2
install –m –d /testdir/installdir
bash如何展開命令行()流程
?把命令行分成單個命令詞
?展開別名
?展開大括號種的聲明( {})
?展開波浪符聲明( ~)
?命令替換$() 和 “)
?再次把命令行分成命令詞
?展開文件通配( *、 ?、 [abc]等等)
?準備I/0重導向( <、 >)
?運行命令
防止擴展
?反斜線( \)會使隨后的字符按原意解釋
$ echo Your cost: \$5.00
Your cost: $5.00
?加引號來防止擴展
? 單引號( ’)防止所有擴展
? 雙引號( ”)也防止所有擴展,但是以下情況例外:
? $(美元符號) - 變量擴展
? `(反引號) - 命令替換
? \(反斜線) - 禁止單個字符擴展
? !(嘆號) - 歷史命令替換
bash的配置文件
? 按生效范圍劃分,存在兩類:
? 全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
? 個人配置:
~/.bash_profile
~/.bashrc
注意:以上文件只針對登錄用戶有效
shell登錄兩種方式
? 交互式登錄:
(1)直接通過終端輸入賬號密碼登錄;
(2)使用“ su – UserName” 切換的用戶
執行順序:
/etc/profile –>/etc/profile.d/*.sh–>~/.bash_profile –>~/.bashrc –>/etc/bashrc
? 非交互式登錄:
(1)su UserName
(2)圖形界面下打開的終端
(3)執行腳本
執行順序:
~/.bashrc –> /etc/bashrc –> /etc/profile.d/*.sh
Profile類
? 按功能劃分,存在兩類:
profiile類和bashrc類
? profile類:為交互式登錄的shell提供配置
全局: /etc/profile, /etc/profile.d/*.sh
個人: ~/.bash_profile
功用:
(1) 用于定義環境變量
(2) 運行命令或腳本
Bashrc類
? bashrc類:為非交互式和交互式登錄的shell提供配置
全局: /etc/bashrc
個人: ~/.bashrc
功用:
(1) 定義命令別名和函數
(2) 定義本地變量
編輯配置文件生效
? 修改profile和bashrc文件后需生效
兩種方法:
1重新啟動shell進程
2 . 或source
例:
. ~/.bashrc
Bash 退出任務
? 保存在~/.bash_logout文件中(用戶)
? 在退出登錄shell時運行
? 用于
創建自動備份
清除臨時文件
二、壓縮和解壓縮工具和程序包管理
壓縮比
目的:時間 換 空間
CPU的時間–> 磁盤空間
服務器CPU時間一般很珍貴,所以不合適
桌面環境則CPU時間大量空閑,所以一般比較合適
compress/uncompreess
后綴名:.Z(早期使用,現在已經淘汰,了解即可)
compress [-dfvcVr] [-b maxbits] [file …]
-d: 解壓縮,相當于
-c: 結果輸出至標準輸出,不刪除原文件
-v: 顯示詳情
? uncompress 解壓縮
? zcat file.Z >file
壓縮解壓縮工具種類:
gzip/gunzip/zcat,后綴名.gz(使用最普遍)
bzip2/bunzip2,后綴名.bz2
xz/unxz,后綴名.xz(壓縮比最大)
lzma/unlzma/lzcat
zip/unzip(既能歸檔又能壓縮)
tar,cpio(歸檔打包)
1、gzip/gunzip/zcat:(需要識別后綴名)
標準格式:
gzip [ -acdfhlLnNrtvV19 ] [-S suffix] [ name … ]
gunzip [ -acfhlLnNrtvV ] [-S suffix] [ name … ]
zcat [ -fhLV ] [ name … ] 查看創建臨時壓縮文件并查看內容
常用使用格式
gzip [OPTION]… FILE…
-d:解壓縮,相當于gunzip;
-#:指定壓縮比,默認是6,數字越大,壓縮比越大(1-9)
-c:將壓縮結果輸出至標準輸出;
可以使用:gzip -c FILE > /PATH/TO/SOMEFILE.gz既保留原文件又壓縮
實例:
gzip -c messages >messages.gz
gzip -c -d messages.gz > messages
zcat messages.gz > messages
注意:zcat僅適合查看小文件
2、bzip2/bunzip2/bzcat
標準格式:
bzip2 [ -cdfkqstvzVL123456789 ] [ filenames … ]
bunzip2 [ -fkvsVL ] [ filenames … ]
bzcat [ -s ] [ filenames … ] 查看創建臨時壓縮文件并查看內容
bzip2recover filename 修復數據的,但是修復能力有限
常用格式:
bzip2 [OPTION]… FILE…
-d:解壓縮,相當于bunzip2;
-#:指定壓縮比,默認是6,數字越大,壓縮比越大(1-9)
-k:keep,保留原文件
3、xz/unxz/xzcat
lzma/unlzma/lzcat
xz [option]… [file]…
unxz is equivalent to xz –decompress.
xzcat is equivalent to xz –decompress –stdout. 查看創建臨時壓縮文件并查看內容
lzma is equivalent to xz –format=lzma.
unlzma is equivalent to xz –format=lzma –decompress.
lzcat is equivalent to xz –format=lzma –decompress –stdout.
xz [option]… [file]…
-d:解壓縮,相當于unxz;
-#:指定壓縮比,默認是6,數字越大,壓縮比越大(1-9)
-k:keep,保留原文件
注意:以上壓縮工具默認只能壓縮文件,不能壓縮目錄
壓縮能力:xz > bzip2 > gzip 但是bzip2算法極占資源
歸檔工具:tar,cpio
tar命令:
tar [OPTION…] [FILE]…
tar選項可以不帶-
(1)創建歸檔
-c -f /PATH/TO/SOMEFILE.tar FILE…
-cf /PATH/TO/SOMEFILE.tar FILE…
歸檔路徑 目標文件
-f -c 不可以,參數就變成-c的了
(2)展開歸檔
-xf /PATH/TO/SOMEFILE.tar 展開至當前目錄
-xf /PATH/TO/SOMEFILE.tar -C /PATH/TO/SOMEDIR 展開至指定目錄
(3)查看歸檔文件的文件列表
-tf /PATH/TO/SOMEFILE.tar
-tvf /PATH/TO/SOMEFILE.tar
歸檔完成后通常需要壓縮,結合此前的壓縮工具,就能實現壓縮多個文件和目錄
-j: bzip2, -z: gzip, -J: xz
(4)歸檔并壓縮
-z:gzip2
創建歸檔并壓縮
-zcf /PATH/TO/SOMEFILE.tar.gz FILE…
解壓縮并展開歸檔
-zxf /PATH/TO/SOMEFILE.tar.gz
-xf /PATH/TO/SOMEFILE.tar.gz
-j:bzip2
創建歸檔并壓縮
-jcf /PATH/TO/SOMEFILE.tar.gz FILE…
解壓縮并展開歸檔
-jxf /PATH/TO/SOMEFILE.tar.bz2
-xf /PATH/TO/SOMEFILE.tar.bz2
-J:xz
創建歸檔并壓縮
-Jcf /PATH/TO/SOMEFILE.tar.xz FILE…
解壓縮并展開歸檔
-Jxf /PATH/TO/SOMEFILE.tar.xz
-xf /PATH/TO/SOMEFILE.tar.xz
注意:解壓縮并展開歸檔時,可以省略z,j,J,直接使用xf,解壓時可以自動識別文件壓縮格式
?
cpio工具:復制 從或到文件
cpio命令是通過重定向的方式將文件進行打包備份,還原恢復的工具,它可以解壓以“ .cpio”或者“ .tar”結尾的文件。
cpio [選項] > 文件名或者設備名
cpio [選項] < 文件名或者設備名
選項
-o 將文件拷貝打包成文件或者將文件輸出到設備上
-i 解包,將打包文件解壓或將設備上的備份還原到系統
-t 預覽,查看文件內容或者輸出到設備上的文件內容
-v 顯示打包過程中的文件名稱。
-d 解包生成目錄,在cpio還原時,自動的建立目錄
-c 一種較新的存儲方式
zip:既能歸檔又能壓縮
zip/unzip
后綴名;.zip
打包壓縮
zip –r sysconfig.zip sysconfig/
解包解壓縮
unzip sysconfig.zip
cat /var/log/messages | zip message –
unzip -p message > message
練習:下載redis-3.0.2.tar.gz ,展開至/tmp目錄;而后得新創建壓縮為xz格式;
tar zxfredis-3.0.2.tar.gz -C /tmp xz -k redis-3.0.2.tar
API:Application Progam Interface
API:Application Binary Interface
Unix-like,
ELF
windows
exe,msi
庫級別的虛擬化:
linux:運行windows需要WinE
Windows:運行linux需要Cywin
系統級開發:
C/C++:http,sftpd,nginx
go
應用級開發:
java:hadoop,hbase(jvm)
Python:openstack,(pvm)
perl:(perl解釋器)
ruby:(ruby)
php:(php)
C/C++程序格式:
源代碼:文本格式的程序代碼;
編譯開發環境:編譯器、頭文件、開發庫
二進制格式:文本格式的程序代碼–>編譯器–>二進制格式(二進制程序、庫文件、配置文件、幫助文件)
java/python程序格式:
源代碼:編譯成能夠在其虛擬機(jvm/pvm)運行的格式;
開發環境:編譯器、開發庫
二進制
項目構建工具:
C/C++:make
java:maven
程序包管理器:
源代碼–>目標二進制格式–>組織成為一個或有限幾個“包”文件;
安裝、升級、卸載、查詢、校驗
程序包管理器:
debian:dpt,dpkg,".deb"
redhat:redhat package manager,rpm,".rpm" rpm is package manager
S.uS.E:rpm(但是和redhat不兼容(路徑和組織格式不兼容)),".rpm"
Gentoo:ports
ArchLinux:(新興輕量級)
源代碼:name-version.tar.gz
VERSION:major.minor.release
主版本號(重大版本分支).次版本號(有一半以上修改).發型號(bug或代碼改進)
rpm包命名格式:
name-VERSION-release.arch.rpm
VERSION:major.minor.release
release.arch:rpm包的發型號
release.os:2.el7.i386.rpm(第幾次制作.應用平臺.應用架構)
archetecture:i386,x64(mad64),ppc,noarch
常見的arch:
x86: i386, i486, i586, i686
x86_64: x64, x86_64, amd64
powerpc: ppc
跟平臺無關: noarch
包:分類和拆包
Application-VERSION-ARCH.rpm: 主包
Application-devel-VERSION-ARCH.rpm 開發子包
Application-utils-VERSION-ARHC.rpm 其它子包
Application-libs-VERSION-ARHC.rpm 其它子包
? 包之間:可能存在依賴關系,甚至循環依賴
例如
x,y,z
x–>y,z
y–>A,B,C
C–>Y
解決包之間依賴關系所帶來的諸多不便,而誕生了相應的前端工具
前端工具:自動解決依賴關系;
yum:rhel系列系統上rpm包管理器的前端工具;
apt-get(apt-cache):deb包管理器的前端工具;
zypper:suse的rpm管理器前端工具;
dnf:Fedor22+系統上rpm包管理器的前端工具;yum之后的新型前端工具
程序包管理器:
功能:將編譯好的應用程序的各組成文件打包成一個或幾個程序包文件,從而更方便地實現程序包的安裝、升級、卸載和查詢等管理操作;
1、程序包的組成清單(每個程序包的單獨實現);
文件清單
安裝和卸載時運行的腳本
2、數據庫(公共)
程序包的名稱和版本
依賴關系
功能說明
安裝生成的個文件的文件路徑及校驗碼信息;
查看二進制程序所依賴的庫文件:
ldd /PATH/TO/BINARY_FILE
管理及查看本機裝載的庫文件:
ldconfig
/sbin/ldconfig -p: 顯示本機已經緩存的所有可用庫文件
名及文件路徑映射關系
配置文件: /etc/ld.so.conf, /etc/ld.so.conf.d/*.conf
緩存文件: /etc/ld.so.cache
centos7 rpm數據庫位置:/var/lib/rpm/
獲取程序包的途徑:
(1)系統發行版的光盤或官方的文件服務器(或鏡像站點);
http://mirrors.aliyun.com;
http://mirrors.sohu.com;
http://mirrors.163.com;
(2) 項目的官方站點
www.Zabbix.com
httpd.apache.org
(3)第三方組織:
(a)EPEL
(b)Rpmforge:RHEL推薦,包很全
(c)搜索引擎
http://pkgs.org
http://rpmfind.net
http://rpm.pbone.net
(4) 自動動手
建議:檢查其合法性
來源合法性;
程序包的完整性;
CentOS系統上rpm命令管理程序包:
安裝、升級、卸載、查詢和校驗、數據庫維護
rpm命令:rpm [OPTIONS] [PACKAGE_FILE]
安裝:-i,–install
升級:-U,–update,-F,-freshen
卸載:-e,erase
查詢:-q,–query
校驗:-V,–verify
安裝:
rpm {-i|–install} [install-options] PACKAGE_FILE …
rpm -ivh PACKAGE_FILE …
GENERAL OPTIONS:通用選項
-v:verbose,詳細信息
-vv:更詳細的輸出
[install-options]
-h:hash marks輸出進度條;每個#表示2%的進度;
-test:測試安裝,但不真正執行安裝; dry run模式;檢查并報告依賴關系及沖突信息等
–nodeps:忽略依賴關系;不建議使用
–replacepkgs| replacefiles:重新安裝(不需要卸載,不能替換配置文件)
–nosignature: 不檢查來源合法性
–nodigest:不檢查包完整性
注意:rpm可以自帶腳本
四類: –noscripts:不執行程序包腳本
preinstall:安裝過程開始之前運行的腳本;%pre,–nopre
postinstall:: 安裝過程完成之后運行的腳本; %post,–nopost
preuninstall:: 卸載過程真正開始執行之前運行的腳本; %preun,–nopreun
postuninstall:: 卸載過程完成之后運行的腳本; %postun,–nopostun
升級:
rpm {-U|–upgrade} [install-options] PACKAGE_FILE…
rpm {-F|–freshen} [install-options] PACKAGE_FILE…
upgrade:安裝有舊版程序包,則“升級”
如果不存在舊版程序包,則“安裝”
freshen:安裝有舊版程序包,則“升級”
如果不存在舊版程序包,則不執行升級操作
rpm -Uvh PACKAGE_FILE …
rpm -Fvh PACKAGE_FILE …
–oldpackage:降級
–force: 強行升級
注意:
(1) 不要對內核做升級操作; Linux支持多內核版本并存,因此,對直接安裝新版本內核
(2) 如果原程序包的配置文件安裝后曾被修改,升級時,新版本的提供的同一個配置文件并不會直接覆蓋老版本的配置文件,而把新版本的文件重命名(FILENAME.rpmnew)后保留
卸載:
rpm {-e|–erase} [–allmatches] [–nodeps] [–noscripts] [–notriggers] [–test] PACKAGE_NAME …
–allmatches:卸載所有匹配指定名稱的程序包的各版本;
–nodeps:忽略依賴關系
–test:測試卸載,dry run模式
查詢
rpm {-q|–query} [select-options] [query-options]
[select-options]
-a: 查詢所有已經安裝過的包
-f: 查看指定的文件由哪個程序包安裝生成
-g:查詢指定包組都有哪些包
-p rpmfile:針對尚未安裝的程序包文件做查詢操作;
–whatprovides CAPABILITY:查詢指定的CAPABILITY由哪個包所提供
–whatrequires CAPABILITY:查詢指定的CAPABILITY被哪個包所依賴
rpm2cpio 包文件|cpio –itv 預覽包內文件
rpm2cpio 包文件|cpio –id “ *.conf” 釋放包內文件
[query-options]
–changelog:查詢rpm包的changelog
-c: 查詢程序的配置文件
-d,–docfiles: 查詢指定程序包的文檔
-i: information:查詢程序包相關的信息、版本號、大小、所屬的包組等
-l,list: 查看指定的程序包安裝后生成的所有文件;
–scripts:查詢程序包自帶的腳本片段
-R,–requires: 查詢指定的程序包所依賴的CAPABILITY;
–provides: 列出指定程序包所提供的CAPABILITY;
PACKAGE_NAME:查詢指定的程序包是否已經安裝,及其版本;
查詢用法:
-qi PACKAGE
-qf FILE
-qc PACKAGE
-ql PACKAGE
-qd PACKAGE
-qpi PACKAGE_FILE
-qpl PACKAGE_FILE
-qpc PACKAGE_FILE, …
-qa
校驗
? rpm {-V|–verify} [select-options] [verify-options]
S file Size differsda 文件大小
M Mode differs (includes permissions and file type) 權限
5 digest (formerly MD5 sum) differs MD5碼
D Device major/minor number mismatch 主次設備號
L readLink(2) path mismatch readLink路徑
U User ownership differs 屬主所有權
G Group ownership differs 屬組所有權
T mTime differs 更新時間
P capabilities differ. 能力
包來源合法性驗正及完整性驗正:
完整性驗正: SHA256
來源合法性驗正: RSA
公鑰加密:
對稱加密:加密、解密使用同一密鑰;
非對稱加密:密鑰是成對兒的
public key: 公鑰,公開所有人
secret key: 私鑰, 不能公開
過程
1、單向加密程序包獲得特征碼
2、用自己的私鑰加密特征碼
3、附加到程序后面
4、用公鑰解密獲得特征碼
5、獲取程序特征碼與解密后的特征碼比較
導入所需要公鑰:
rpm –import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 導入公鑰
CentOS 7發行版光盤提供: RPM-GPG-KEY-CentOS-7
rpm -qa gpg-pubkey*
驗證:
(1)安裝此組織簽名的程序時,會自動執行驗證
(2)手動驗證:rpm -K|checksig rpmfile 檢查包的完整性和簽名
rpm數據庫
? 數據庫重建:
/var/lib/rpm
rpm {–initdb|–rebuilddb} [-v] [–dbpath DIRECTORY] [–root DIRECTORY]
initdb: 初始化
如果事先不存在數據庫,則新建之
否則,不執行任何操作
rebuilddb: 重建已安裝的包頭的數據庫索引目錄
獲取幫助:
centos 6:man rpm
centos 7:man rpmdb
eg:
rpm –initdb –dbpath=/tmp/rpm
rpm –rebuilddb –dbpath=/tmp/rpm
yum
? CentOS: yum, dnf
? YUM: Yellowdog Update Modifier, rpm的前端程序,用來
解決軟件包相關依賴性,可以在多個庫之間定位軟件包,
up2date的替代工具
yum repository: yum repo,存儲了眾多rpm包,以及
包的相關的元數據文件(放置于特定目錄repodata下)
文件服務器:
ftp:// ftp服務器
http:// web服務器
file:/// 本地服務器
yum配置文件
? yum客戶端配置文件:
/etc/yum.conf:為所有倉庫提供公共配置
/etc/yum.repos.d/*.repo:為倉庫的指向提供配置
倉庫指向的定義:
[repositoryID]
name=Some name for this repository
baseurl=url://path/to/repository/
enabled={1|0}
gpgcheck={1|0}
gpgkey=URL
enablegroups={1|0}
failovermethod={roundrobin|priority}
默認為: roundrobin,意為隨機挑選;
cost= 默認為1000
yum命令的用法:
yum [options] [command] [package …]
yum-config-manager
yum-config-manager –disable “倉庫名" 禁用倉庫
yum-config-manager –enable “倉庫名” 啟用倉庫
顯示倉庫列表:
repolist [all|enabled|disabled]
? 顯示程序包:
list
# yum list [all | glob_exp1] [glob_exp2] […]
# yum list {available|installed|updates} [glob_exp1]
[…]
? 安裝程序包:
install package1 [package2] […]
reinstall package1 [package2] […] (重新安裝)
yum
? 升級程序包:
update [package1] [package2] […]
downgrade package1 [package2] […] (降級)
? 檢查可用升級:
check-update
? 卸載程序包:
remove | erase package1 [package2] […]
查看程序包information:
info […]
? 查看指定的特性(可以是某文件)是由哪個程序包所提供:
provides | whatprovides feature1 [feature2] […]
? 清理本地緩存:
clean [ packages | metadata | expire-cache |
rpmdb | plugins | all ]
? 構建緩存:
makecache
搜索: search string1 [string2] […]
以指定的關鍵字搜索程序包名及summary信息
? 查看指定包所依賴的capabilities:
deplist package1 [package2] […]
? 查看yum事務歷史:
history [info|list|packages-list|packages-info|
summary|addon-info|redo|undo|
rollback|new|sync|stats]
yum history
yum history info 6
yum history undo 6
? 日志 : /var/log/yum.log
安裝及升級本地程序包:
localinstall rpmfile1 [rpmfile2] […]
(用install替代)
localupdate rpmfile1 [rpmfile2] […]
(用update替代)
包組管理的相關命令:
groupinstall group1 [group2] […]
groupupdate group1 [group2] […]
grouplist [hidden] [groupwildcard] […]
groupremove group1 [group2] […]
groupinfo group1 […]
如何使用光盤當作本地yum倉庫:
(1) 掛載光盤至某目錄,例如/media/cdrom
# mount /dev/cdrom /media/cdrom
(2) 創建配置文件
[CentOS7]
name=
baseurl=
gpgcheck=
enabled=
yum的命令行選項:
–nogpgcheck:禁止進行gpg check
-y: 自動回答為“ yes”
-q:靜默模式
–disablerepo=repoidglob:臨時禁用此處指定的repo
–enablerepo=repoidglob:臨時啟用此處指定的repo
–noplugins:禁用所有插件
yum倉庫
yum的repo配置文件中可用的變量:
$releasever: 當前OS的發行版的主版本號
$arch: 平臺, i386,i486,i586,x86_64等
$basearch:基礎平臺; i386
$YUM0-$YUM9:自定義變量
創建yum倉庫:
createrepo [options] <directory>
程序包編譯安裝:
? Application-VERSION-release.src.rpm –> 安裝后,使
用rpmbuild命令制作成二進制格式的rpm包,而后再安裝
? 源代碼–>預處理–>編譯(gcc)–>匯編–>鏈接–>執行
? 源代碼組織格式:
多文件:文件中的代碼之間,很可能存在跨文件依賴關系
C、 C++: make (項目管理器, configure –>
Makefile.in –> makefile)
java: maven
編譯安裝
? C代碼編譯安裝三步驟:
1、 ./configure:
(1) 通過選項傳遞參數,指定啟用特性、安裝路徑等;執
行時會參考用戶的指定以及makefile.in文件生成makefile
(2) 檢查依賴到的外部環境
2、 make:根據makefile文件,構建應用程序
3、 make install:復制文件到相應路徑
? 開發工具:
autoconf: 生成configure腳本
automake:生成Makefile.in
? 注意:安裝前查看INSTALL, README
select
select 循環與菜單
?select variable in list
do
循環體命令
done
?select 循環主要用于創建菜單,按數字順序排列的
菜單項將顯示在標準錯誤上,并顯示 PS3 提示符,
等待用戶輸入
? 用戶輸入菜單列表中的某個數字,執行相應的命令
? 用戶輸入被保存在內置變量 REPLY 中。
select 與 case
?select 是個無限循環,因此要記住用 break 命令退
出循環,或用 exit 命令終止腳本。也可以按 ctrl+c
退出循環。
?select 經常和 case 聯合使用
?與 for 循環類似,可以省略 in list , 此時使用位置參量
作業:
1、1、編寫服務腳本/root/bin/testsrv.sh,完成如下要求
(1) 腳本可接受參數:start, stop, restart, status
(2) 如果參數非此四者之一,提示使用格式后報錯退出
(3) 如是start:則創建/var/lock/subsys/SCRIPT_NAME, 并顯示“啟動成功”
考慮:如果事先已經啟動過一次,該如何處理?
(4) 如是stop:則刪除/var/lock/subsys/SCRIPT_NAME, 并顯示“停止完成”
考慮:如果事先已然停止過了,該如何處理?
(5) 如是restart,則先stop, 再start
考慮:如果本來沒有start,如何處理?
(6) 如是status, 則如果/var/lock/subsys/SCRIPT_NAME文件存在,則顯示“SCRIPT_NAMEis running…”
如果/var/lock/subsys/SCRIPT_NAME文件不存在,則顯示“SCRIPT_NAME is stopped…”
其中:SCRIPT_NAME為當前腳本名
#bin/bash # prog=$(basename $0) lockfile=/var/lock/subsys/$prog start() { if [ -e $lockfile ];then echo "$prog is aleady running." return 0 else touch $lockfile [ $? -eq 0 ] && echo "Staring $prog finished." fi } stop() { if [ -e $lockfile ];then rm -f $loackfile &&echo "Stop $prog ok." else echo "$prog is stopped yet." } status() { if [ -f $lockfile ];then echo "$prog is running." else echo "$prog is stoped." fi } usage() { echo "USage: $prog {start|stop|restart|status}" } case $1 in start) start ;; stop) stop ;; restatrt) stop start;; status) status;; *) usage exit 1 ;; esac
2、編寫腳本/root/bin/copycmd.sh
(1) 提示用戶輸入一個可執行命令名稱;
(2) 獲取此命令所依賴到的所有庫文件列表
(3) 復制命令至某目標目錄(例如/mnt/sysroot)下的對應路徑下;
如:/bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd==> /mnt/sysroot/usr/bin/passwd
(4) 復制此命令依賴到的所有庫文件至目標目錄下的對應路徑下:
如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
(5)每次復制完成一個命令后,不要退出,而是提示用戶鍵入新的要復制的命令,并重復完成上述功能;直到用戶輸入quit退出
#!/bin/bash ch_root="/mnt/sysroot" [ ! -d $ch_root ] && mkdir $ch_root bincopy() { if which $1 &>/dev/null;then local cmd_path=`which --skip-alias $1` local bin_dir=`dirname $cmd_path` [ -d ${ch_root}${bin_dir} ] ||mkdir -p ${ch_root}${bin_dir} [ -f ${ch_root}${cmd_dir} ] ||cp $cmd_path ${ch_root}${bin_dir} return 0 else echo "Command not found." return 1 fi } libcopy() { local lib_list=$(ldd `which --skip-alias $1` |grep -Eo '/[^[:space:]]+') for loop in $lib_list;do local lib_dir=`dirname $loop` [ -d ${ch_root}${lib_dir} ] ||mkdir -p ${ch_root}${lib_dir} [ -f ${ch_root}${loop} ] || cp $loop ${ch_root}${lib_dir} done } read -p "Please input a command:" command while [ "$command" !="quit" ];do if bincopy $command;then libcopy $command fi read -p "Please input a command or quit:" command done
3、漢諾塔(又稱河內塔)問題是源于印度一個古老傳說。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。并且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。
利用函數,實現N片盤的漢諾塔的移動步驟
#!/bin/bash # step=0 move() { let step++ echo "$step: move disk $1 $2-------->$3" } hanoi() { if [ $1 -eq 1 ];then move $1 $2 $4 else hanoi "$[$1-1]" $2 $4 $3 move $1 $2 $4 hanoi "$[$1-1]" $3 $2 $4 fi } read -p "please input the number of plates:" number hanoi $number A B C
或者
#!/bin/bash # step=0 hanoi() { [[ ! $1 =~ ^[1-9][]0-9]*$ ]]&&echo "Error! please input a positive interger" && exit if [ $1 -eq 1 ];then let step++ echo "$step: move disk $1 $2-------->$3" else hanoi "$[$1-1]" $2 $4 $3 let step++ echo "$step: move disk $1 $2-------->$3" hanoi "$[$1-1]" $3 $2 $4 fi } read -p "please input the number of plates:" number hanoi $number A B C
原創文章,作者:NameLess,如若轉載,請注明出處:http://www.www58058.com/39914