不用編譯,解釋執行
不用 ; 標識該行結束,但本應另起一行的寫到同一行則需要加 ; 如:
if test $age -le 2; then
?
常用的Shell:sh、csh、tcsh、ash、bash
查看當前shell:echo $SHELL;查看當前系統默認shell:echo $0
bash程序放在/bin或/usr/bin,/etc/shells記錄系統可用的shell
chsh -s /usr/bin/fish 修改默認shell
內部命令:
type顯示命令類型(內部外部) test檢查某個條件是否成立
break continue read printf echo return exit logout wait
cd pwd source help history jobs kill date set 等
給命令創建別名:
????alias ????????????????????# 直接用顯示當前Shell中使用了哪些別名
????alias grep=`grep --color=auto`
????unalias grep ????????# 刪除別名,-a 刪除所有別名
?
登錄用戶的權限等級(超級用戶:#,普通用戶:$)
臨時修改提示符:修改環境變量PS1(默認為'[?W]$')和PS2(第二層,默認為>)
?an>
?
Shell四種運行方式:
1.a交互式的登錄Shell、b交互式的非登錄Shell、非交互式的登錄Shell、非交互式的非登錄Shell
2.判斷是否交互式:查看變量 $- 的值,含 i 則為交互式
或查看PS1的值,非空則為交互式
3.判斷是否登錄式:shopt login_shell,值為on表登錄式,off非登錄式
注:輸入bash執行時,默認為非登錄式,加選項--login(-l)可變為登錄式
由()包圍的組命令或者命令替代進入子shell時,會繼承父shell的交互和登錄屬性
?
Shell配置文件的加載:
1.Bash Shell在啟動時,需加載相關啟動文件配置其運行環境,如初始化環境變量、設置命令提示符、指定系統路徑等,這些配置文件其實也是腳本文件,不同的啟動方式會加載不同的配置文件
2.登錄式:全局配置文件/etc/profile(嵌套加載/etc/profile.d/*.sh)、
個人配置文件(一個即可,優先加載順序 ~/.bash_profile(嵌套加載~/.bashrc) 或 .bash_login 或 .profile)
非登錄式:直接讀取~/.bashrc(嵌套加載/etc/bashrc)
3.編寫自己的Shell配置文件:無論有無登錄都會加載~/.bashrc,可添加代碼到該文件中(或引入 . https://www.bilibili.com/read/cv14608862/myconf.sh)
?
在Bash Shell中,不用指明變量類型,每個變量的值都是字符串的形式存儲(無論有無加引號)
1.定義變量同時賦值:var1=fang / 'fang' / "fang" # =周圍不能有空格
區別:
方式1也會對變量進行解析,但串中不能出現空格
含空白符時需加引號,單引號會把字符串原樣輸出,且串中不能出現單引號,即使進行轉義也不行
而雙引號會解析串中的變量和命令,可以出現單引號、雙引號(須被轉義)
?
2.:echo $var1 / ${var1}
$用于調用變量,加花括號可以幫助編譯器在字符串中識別變量邊界
刪除變量:unset var2 # 無法刪除只讀變量
?
3.有時有必要顯示聲明變量類型:declare [選項] var1
-r:只讀 -i:整數 -a:數組 -f:函數 -x:作為腳本的環境變量被導出
只讀變量:readonly var1
?
:將命令的輸出結果賦值給變量
command中,命令可有多個,用 ; 隔開
var2=`date +%s`
var2=$(command) (支持嵌套,``不行,僅Bash Shell支持)
當被替換的命令的輸出內容有多行(有換行符),或有多個空白符,那么在輸出變量時,應將變量用雙引號包圍,否則系統會使用默認的空白符來填充(導致換行無效,連續空白符被壓縮成一個)
?
1)字符串拼接:
????str1="20""22"jiayou$me ??????????????# 并排放在一起即可
????str1=$name$url ?????????????????????????# 中間不能有空格
????str2="$name $url" ?????????????????????# 中間可以有空格
2)字符串截取:
????${變量名:start:length} ????????????????# index從0開始,含左,右為-1,length不寫截到最后
---掐頭去尾:
????${變量名#*子串}???????????????????????? # 刪除開頭到子串第一次出現的所有字符
????${變量名##*子串} ??????????????????????# 到字串最后一次出現
????${變量名%子串} ????????????????????????# 刪除結尾到子串第一次出現的所有字符
????${變量名%%子串}
3)子串替換:?? ??
????${變量名/old/new} # 只替換第一個匹配的結果
????${變量名//old/new} # 替換全部匹配結果
4) ${#變量名} # 獲取字符串長度
:不限制定義和調用的順序,調用可以在定義的前面
#! /bin/bash #!用什么解釋器執行
????function 函數名() {
????????//TODO,read PERSON # 從標準輸入中讀取并賦值給變量
????????echo "Hello, $PERSON"
????????[return value]
????}
????函數名 [參數1 參數2 參數3 ...] ????????????????# 調用
參數:函數在定義時不能/不用指明參數,但在調用時卻可以傳遞參數
返回值:返回的應是函數的執行狀態,0成功,非0失敗(0~255)
沒有return語句,返回默認的退出狀態,即最后一條命令的退出狀態return $?
if、while、for等語句常常根據函數的退出狀態來判斷條件是否成立
那么,如何得到函數的處理結果:
(1)借助全局變量,保存到外部進行輸出
(2)在函數內部使用 echo、printf 命令將結果輸出,在函數外部使用$()或者``捕獲結果
?
????https://www.bilibili.com/read/cv14608862/test.sh ????????????????????????????# 在新進程中運行,先當前目錄再到系統路徑查找
????bash test.sh??????????????????????# 直接查找系統路徑
????source或. https://www.bilibili.com/read/cv14608862/test.sh ????????????# 在當前進程中運行,會強制執行,忽略腳本文件的權限
?
1)在腳本文件內部可用的:
$n (n=1,2,3...) # 位置變量,接收命令傳參,$1表示第一個參數
$# # 參數個數
$0 # 當前腳本文件名
$$ # 當前Shell進程的進程ID
$* / $@ # 代表傳遞的所有參數,當被雙引號" "包含時,會有區別:
????"$*" 將所有的參數從整體上看做一份數據
????"$@" 將每個參數都看作一份數據,彼此之間是獨立的,for n in $@
$? # 上個命令的退出狀態(0表執行成功,非0表執行失敗)
?
2):內容較長,見06Shell補充進階
?
3):
????默認換行,不想換行可加-n
????默認不解析以開頭的轉義字符,加-e將進行解析(可以在字符串中加c強制echo不換行)
?
4):用來檢測某個條件是否成立(成立返回 0 值),常和 if 語句一起使用,可以進行數值、字符串和文件三個方面的檢測,test 命令也可簡寫為:
[ expression ] # 兩邊的空格不能去掉
注,test 只能用來比較整數,小數相關的比較還得依賴?bc 命令
????????在 test 中使用變量建議用雙引號包圍起來
????????test 命令比較奇葩,>、<、== 只能用來比較字符串,不能用來比較數字,比較數字需要使用 -eq、-gt 等選項;不管是比較字符串還是數字,test 都不支持 >= 和 <=
舉例:
if test -w $filename && test -n $url
if test $a -eq $b
if [ -z "$str1" ] || [ -z "$str2" ] ??????????????# 用雙引號包圍,防止為空字符串出現錯誤
if [ $str1 = $str2 ]
if [ -z "$str1" -o -z "$str2" ] ????????????????# 使用 -o 選項取代之前的 ||
?
,使用?source 命令來實現把代碼分散到多個文件或文件夾,該命令會強制執行腳本文件中的全部命令,而忽略腳本文件的權限
????source或. filename
1)實例:
創建兩腳本文件 func.sh(包含了若干函數) 和 main.sh(主文件),main.sh 中會包含 func.sh
#計算所有參數的和
function sum(){
????local total=0
????for n in $@
????do
????????((total+=n))
????done
????echo $total
????return 0
}
?
main.sh:
#!/bin/bash
source func.sh # 可使用相對路徑或絕對路徑
echo $(sum 10 20 55 15)
運行 main.sh,輸出結果為:100
避免重復引入:即使被多次引入,效果也相當于一次引入,略
?
為了表示和區分已經打開的文件,Linux會給每個文件分配一個ID(稱文件描述符): 0 stdin 標準輸入,默認指向鍵盤
1 stdout 標準輸出,顯示器 2 stderr 標準錯誤輸出,顯示器
輸出:
????ls -l 代碼>file ????????????????????????????# 輸出重定向,代碼fd不寫默認為1,>覆蓋,>>追加,代碼和>之間不能有空格,>和file之間的空格可有可無
????ls -l 1>>file
????ls -l 2>file
????ls -l 2>>file
?
????ls -l >file 2>&1? ?????????????????????????# 標準輸出和錯誤信息保存在同一文件中
????command >>file 2>&1
????command >file 2>file???????????????? # 不推薦,會導致file被打開兩次
????command >>file 2>>file
?
????command >file1 2>file2???????????? # 標準輸出和錯誤信息輸出到不同文件中
????command >>file1 2>>file2
?
????command &>/dev/null???????????????# 將二者重定向到垃圾箱
?
1.exec命令可持久性的進行重定向(對當前Shell進程的所有命令都有效),修改后須手動進行恢復
????exec 文件描述符操作(>log.txt)
????exec >/dev/tty # 恢復,或:
????exec >&2
#!/bin/bash
sum=0
while read n; do
????((sum += n))
????echo "this number: $n"
done <nums.txt >log.txt ????????????# 同時使用輸入輸出重定向,代碼塊內得有輸入/輸出語句
echo "sum=$sum"
?
command <<END # <<END是開始,同時指明結束標志為END,可自定義
document # 命令需要處理的數據
END # 須獨占一行,且頂格寫
注:
忽略命令替換:document內的變量和指令,默認會先解析替換,再交由command執行
可用單/雙引號將結束符圍起來,將不再解析,<<'END'
忽略制表符:默認行首的制表符Tab也會被視為正文的一部分,若不想,可在<<和END之間增加-,<<-END
?
內嵌文檔的變種(更便捷,特別是發送變量內容(而不是文件),到grep等過濾命令
command <<< name
?
為什么使用:連接多個程序或命令的輸入與輸出,簡潔,且可以避免創建中間臨時文件,從管道輸出的標準錯誤會混合到一起
常和grep、輸入輸出重定向一起使用:
ls -al | grep log.txt >output.txt、command1 < input.txt | command2
?
(結合管道符,對文件內容進行):
sort 對文本文件的行進行排序
uniq 忽略重復的行
wc 打印文件總行數、單詞數或字節數
tr 轉換或刪除字符
head 讀取文件開頭(默認10行),不指定文件,則從標準輸入讀取
tail 顯示文件的結尾部分
more
cut 將輸入文件每行的指定部分輸出到標準輸出
grep "bin/bash" /etc/passwd | cut -d: -f1,6 root:/root fangzehou:/home/fangzehou
tar 對文件進行歸檔
?
grep 搜索一個/多個 文件中匹配指定模式的行
sed 過濾和轉換文本的流編輯器
awk 用于文本處理的解釋性程序設計語言,通常被作為數據提取和報告的工具