Shell(Unix Shell)是一種命令行解釋器,是Unix操作系統(tǒng)下最傳統(tǒng)的人機(jī)接口。
Shell腳本是解釋執(zhí)行的,不需要編譯,和大部分的編程語(yǔ)言很相似,也有基本的變量和流程控制語(yǔ)句。
平時(shí)使用
Shell有兩種方式:
- 輸入命令,執(zhí)行,這種方式稱為交互式(
Interactive);- 批處理(
Batch)方式,用戶事先寫好Shell腳本文件,然后順序執(zhí)行腳本中的命令。
第一個(gè)
Shell環(huán)境是Thompson Shell,在貝爾實(shí)驗(yàn)室開(kāi)發(fā)并于1971年發(fā)布現(xiàn)代
Shell最突出的祖先是被稱為sh的BourneShell,這是以在AT&T工作的創(chuàng)始人Stephen Bourne命名的
Shell一直在基于這個(gè)概念,不斷添加各種新功能,演變出很多種的Shell
例如:很早版本的
OS X中使用的是:
tcsh作為默認(rèn)的Shell。這是由csh(C shell),一種類似C語(yǔ)言的Shell演變而來(lái)在
OS X 10.3版與10.4版之后,默認(rèn)的Shell是:
bash,由GNU開(kāi)發(fā)除了默認(rèn)的
bash,現(xiàn)在macOS中,默認(rèn)的Shell變成了zsh這是一種由
Paul Falstad于1990年開(kāi)發(fā)的。它是一個(gè)Bourne式Shell,它使用bash和previous shell的特性,并添加了更多的特性:
- 拼寫檢查功能
- 內(nèi)置的編程特性
- 友好的交互
與此同時(shí),
macOS還提供了很多其他種類的Shell:ls -ls /bin/*sh ------------------------- 680 -r-xr-xr-x 1 root wheel 623472 8 11 2020 /bin/bash 520 -rwxr-xr-x 1 root wheel 529424 8 11 2020 /bin/csh 112 -rwxr-xr-x 1 root wheel 110848 8 11 2020 /bin/dash 1440 -r-xr-xr-x 1 root wheel 1300256 8 11 2020 /bin/ksh 16 -rwxr-xr-x 1 root wheel 31440 8 11 2020 /bin/sh 520 -rwxr-xr-x 1 root wheel 529424 8 11 2020 /bin/tcsh 736 -rwxr-xr-x 1 root wheel 637840 8 11 2020 /bin/zsh
.bashrc、.bash_profile和.zshrc作用與區(qū)別
在使用命令行工具時(shí),我們可能會(huì)遇到一些教程,可能需要你把一些配置寫入到.bashrc、.bash_profile或者.zshrc等。那么這幾個(gè)文件到底有什么作用和區(qū)別?
從文件名稱判斷
.bashrc、.bash_profile是給bash來(lái)使用的。而.zshrc是給zsh來(lái)使用的查看
bash版本:bash ------------------------- The default interactive shell is now zsh. To update your account to use zsh, please run `chsh -s /bin/zsh`. For more details, please visit https://support.apple.com/kb/HT208050. bash-3.2$查看
zhs的安裝路徑:which zsh ------------------------- /bin/zsh查看
bash的安裝路徑:which bash ------------------------- /bin/bash
zsh切換bash,重新打開(kāi)終端即可chsh -s /bin/bash
bash切換zsh,重新打開(kāi)終端即可chsh -s /bin/zsh
交互式登錄和非登錄Shell
當(dāng)調(diào)用
Shell時(shí),Shell從一組啟動(dòng)文件中讀取信息并執(zhí)行命令。讀取什么文件就取決于Shell是作為交互式登錄還是非登錄調(diào)用。換言之,
Shell分為交互式的或非交互式的:
- 交互式
Shell是讀取和寫入到用戶終端的Shell程序,用戶在終端上輸入命令,并在回車后立即執(zhí)行- 非交互式
Shell是與終端不相關(guān)的Shell程序。例如:執(zhí)行腳本時(shí)交互式
Shell可以是登錄Shell,也可以是非登錄Shell當(dāng)用戶通過(guò)
ssh或本地遠(yuǎn)程登錄到終端時(shí),或者使用--login選項(xiàng)啟動(dòng)時(shí),將調(diào)用登錄Shellzsh --login當(dāng)
bash作為交互式登錄Shell調(diào)用時(shí),bash會(huì)先查找/etc/profile文件,如果該文件存在,它將運(yùn)行文件中列出的命令,然后搜索~/.bash_profile、~/.bash_login以及~/.profile文件,順序讀取當(dāng)
bash作為交互式非登錄Shell調(diào)用時(shí),會(huì)讀取~/.bashrccat /etc/profile ------------------------- # System-wide .profile for sh(1) if [ -x /usr/libexec/path_helper ]; then eval `/usr/libexec/path_helper -s` fi if [ "${BASH-no}" != "no" ]; then [ -r /etc/bashrc ] && . /etc/bashrc fi所以說(shuō),
.bashrc和.bash_profile之間的區(qū)別是,.bash_profile當(dāng)bash作為交互式登錄Shell調(diào)用時(shí)被讀取并執(zhí)行,而.bashrc對(duì)于交互式非登錄Shell被執(zhí)行
大多數(shù)
Linux/Unix發(fā)行版都使用~/.profile代替~/.bash_profile。~/.profile所有Shell都讀取該文件,而~/.bash_profile只有bash才會(huì)讀取該文件
~/.zshrc是zsh的交互式Shell的用戶配置
對(duì)于
bash,它們的工作方式如下:
讀取適當(dāng)?shù)膬?nèi)容,執(zhí)行
A,然后執(zhí)行B,然后執(zhí)行C,依此類推。B1,B2,B3表示僅執(zhí)行找到的那些文件中的第一個(gè)。+----------------+-----------+-----------+------+ | |Interactive|Interactive|Script| | |login |non-login | | +----------------+-----------+-----------+------+ |/etc/profile | A | | | +----------------+-----------+-----------+------+ |/etc/bash.bashrc| | A | | +----------------+-----------+-----------+------+ |~/.bashrc | | B | | +----------------+-----------+-----------+------+ |~/.bash_profile | B1 | | | +----------------+-----------+-----------+------+ |~/.bash_login | B2 | | | +----------------+-----------+-----------+------+ |~/.profile | B3 | | | +----------------+-----------+-----------+------+ |BASH_ENV | | | A | +----------------+-----------+-----------+------+ | | | | | +----------------+-----------+-----------+------+ | | | | | +----------------+-----------+-----------+------+ |~/.bash_logout | C | | | +----------------+-----------+-----------+------+
對(duì)于
zsh,它們的工作方式如下:讀取適當(dāng)?shù)膬?nèi)容,執(zhí)行
A,然后執(zhí)行B,然后執(zhí)行C,依此類推。+----------------+-----------+-----------+------+ | |Interactive|Interactive|Script| | |login |non-login | | +----------------+-----------+-----------+------+ |/etc/zshenv | A | A | A | +----------------+-----------+-----------+------+ |~/.zshenv | B | B | B | +----------------+-----------+-----------+------+ |/etc/zprofile | C | | | +----------------+-----------+-----------+------+ |~/.zprofile | D | | | +----------------+-----------+-----------+------+ |/etc/zshrc | E | C | | +----------------+-----------+-----------+------+ |~/.zshrc | F | D | | +----------------+-----------+-----------+------+ |/etc/zlogin | G | | | +----------------+-----------+-----------+------+ |~/.zlogin | H | | | +----------------+-----------+-----------+------+ | | | | | +----------------+-----------+-----------+------+ | | | | | +----------------+-----------+-----------+------+ |~/.zlogout | I | | | +----------------+-----------+-----------+------+ |/etc/zlogout | J | | | +----------------+-----------+-----------+------+
如何確認(rèn)當(dāng)前是登錄還是非登錄
Shell?確認(rèn)當(dāng)前終端
tty使用的Shell類型:echo $0 ------------------------- zsh
- 前面有
-,表示當(dāng)前已登錄- 前面沒(méi)有
-,表示當(dāng)前非登錄使用
login命令登錄login ------------------------- login: Zang Password:***再次查看
echo $0 ------------------------- -zsh
配置建議
bash:
- 將配置選項(xiàng)放到
~/.bashrc中,然后在~/.bash_profile中通過(guò)source調(diào)用
zsh:
- 建議仍然將配置選項(xiàng)放到
~/.bashrc,~/.bash_profile中通過(guò)source調(diào)用,最后在~/.zshrc中source調(diào)用~/.bash_profile
編譯器與解釋器
編譯型語(yǔ)言需要編譯處理:
- 源代碼(
source code)-> 預(yù)處理器(preprocessor)-> 編譯器(compiler)-> 目標(biāo)代碼(object code)-> 鏈接器(Linker)-> 可執(zhí)行程序(executables)
解釋型語(yǔ)言需要解釋器處理:
- 源代碼(
source code)-> 解釋器(interpreter)
Shell初探
Shebang(Hashbang):一個(gè)由井號(hào)和嘆號(hào)構(gòu)成的字符序列#!出現(xiàn)在文本文件的第一行的前兩個(gè)字符#!/bin/bash操作系統(tǒng)的程序加載器會(huì)分析
Shebang后的內(nèi)容,將這些內(nèi)容作為解釋器指令。并調(diào)用該指令,并將載有Shebang的文件路徑作為該解釋器的參數(shù)
env:不同對(duì)操作系統(tǒng),腳本解釋器可能被安裝于系統(tǒng)的不同的目錄,設(shè)置到系統(tǒng)的PATH中
env可以在系統(tǒng)的PATH目錄中查找#!/usr/bin/python #!/usr/bin/env pyhon
- 上述命令,使用在用戶路徑中找到的第一個(gè)
Python版本可以通過(guò)指定版本號(hào):
#!/usr/bin/env pythonX.x
env也可以指定搜索目錄:#!/usr/bin/env -S -P/usr/local/bin:/usr/bin:${PATH} python
- 在
/usr/local/bin、/usr/bin、系統(tǒng)PATH搜索Python
Shell子進(jìn)程:是從父子進(jìn)程的概念出發(fā)的,unix操作系統(tǒng)的進(jìn)程從init進(jìn)程開(kāi)始(init進(jìn)程為1,而進(jìn)程號(hào)0為系統(tǒng)原始進(jìn)程,以下討論的進(jìn)程原則上不包括進(jìn)程0)均有其對(duì)應(yīng)的子進(jìn)程,就算是由于父進(jìn)程先行結(jié)束導(dǎo)致的孤兒進(jìn)程,也會(huì)被init領(lǐng)養(yǎng),使其父進(jìn)程ID為1因?yàn)樗械倪M(jìn)程均有父進(jìn)程,事實(shí)上,所有進(jìn)程的創(chuàng)建,都可視為子進(jìn)程創(chuàng)建過(guò)程。
unix操作系統(tǒng)進(jìn)程的創(chuàng)建,大致都是進(jìn)行fork + exec類系統(tǒng)調(diào)用理解子進(jìn)程的創(chuàng)建執(zhí)行,需要至少細(xì)分到二個(gè)步驟,包括:
- 通過(guò)
fork創(chuàng)建子進(jìn)程環(huán)境,- 通過(guò)
exec加載并執(zhí)行進(jìn)程代碼。
Shell子進(jìn)程(以下均稱subshell):顧名思義,就是在當(dāng)前的Shell下,去打開(kāi)另一個(gè)新Shell
PS1提示符定義:提示符設(shè)置[\u@\h \w \A #\#]\$
\u:用戶賬號(hào)名稱\h:主機(jī)名縮寫\w:完整工作路徑\A:24小時(shí)時(shí)間\#:第幾個(gè)命令\$:提示符,如果是root,提示符為#,否則是$
HOME:代表用戶主文件夾。
SHELL:當(dāng)前使用的是那個(gè)SHELL
PATH:執(zhí)行文件查找路徑查看
PS1提示符:echo $PS1 ------------------------- %{%f%b%k%}$(build_prompt)
read [-pt]:讀取鍵盤變量
-p:提示符-t:等待秒數(shù)寫入:
read website Cat讀取:
echo $website ------------------------- Cat
注釋
單行注釋
# echo "單行注釋"
多行注釋
- 方式一:
: << ! 多行注釋方式一: echo "多行注釋" !
- 方式二:
: << COMMENT 多行注釋方式二: echo "多行注釋" COMMENT
- 方式三:
: ' 多行注釋方式三: echo "多行注釋" '
- 方式四:
if false; then 多行注釋方式四: echo "多行注釋" fi
- 方式五
((0)) && { 多行注釋方式五: echo "多行注釋" }
特殊符號(hào)的使用
雙引號(hào):
""首先,單引號(hào)和雙引號(hào),都是為了解決中間有空格的問(wèn)題。
因?yàn)榭崭裨?code>Shell中作為一個(gè)很典型的分隔符,比如
string1=this is astring,這樣執(zhí)行就會(huì)報(bào)錯(cuò)。為了避免這個(gè)問(wèn)題,因此就產(chǎn)生了單引號(hào)和雙引號(hào)。他們的區(qū)別在于,單引號(hào)將剝奪其中的所有字符的特殊含義,而雙引號(hào)中的$(參數(shù)替換)和反引號(hào)(命令替換與$()作用一樣)是例外。所以,兩者基本上沒(méi)有什么區(qū)別,除非在內(nèi)容中遇到了參數(shù)替換符$和命令替換符反引號(hào)雙引號(hào)常用于包含一組字符串,在雙引號(hào)中,除了
$、\、`(反引號(hào))有特殊含義外,其余字符(如換行符、回車符等)沒(méi)有特殊含義
echo輸出1&2,由于&是Shell中的特殊符號(hào),直接運(yùn)行命令會(huì)報(bào)錯(cuò)的echo 1&2 ------------------------- [1] 56375 1 cd: no such entry in dir stack [1] + 56375 done echo 1可以使用雙引號(hào)
"",以此解決可能會(huì)產(chǎn)生歧義的問(wèn)題echo "1&2" ------------------------- 1&2使用雙引號(hào)
""進(jìn)行多行輸入echo " 1&2 " ------------------------- 1&2
- 輸出時(shí),前后都有回車。因?yàn)閾Q行符、回車符在雙引號(hào)中沒(méi)有特殊含義,也會(huì)直接輸出
反引號(hào):
``反引號(hào)的功能是命令替換,在反引號(hào)
``中的內(nèi)容通常是命令行,程序會(huì)優(yōu)先執(zhí)行反引號(hào)中的內(nèi)容,并使用運(yùn)行結(jié)果替換掉反引號(hào)處的內(nèi)容echo "I am `echo Cat`" ------------------------- I am Cat
- 在按照
Shell從上往下,從左往右執(zhí)行規(guī)則的前提下,優(yōu)先執(zhí)行反引號(hào)``的內(nèi)容
單引號(hào):
''單引號(hào)的功能與雙引號(hào)類似,不過(guò)單引號(hào)中的所有字符都沒(méi)有特殊含義
echo ' i am `echo Cat` ' ------------------------- i am `echo Cat`
- 反引號(hào)
``在單引號(hào)''中沒(méi)有生效,因?yàn)閱我?hào)中的所有字符都沒(méi)有特殊含義
$ + 小括號(hào):$()作用與反引號(hào)
``一樣,也是命令替換echo "i am $(echo Cat)" ------------------------- i am Cat
$ + 雙小括號(hào):$(())
$(())的功能是進(jìn)行算術(shù)運(yùn)算,括號(hào)中的內(nèi)容為數(shù)學(xué)表達(dá)式echo "20 + 5 * 6 = $((20 + 5 * 6))" ------------------------- 20 + 5 * 6 = 50
$((20 + 5 * 6))返回雙括號(hào)內(nèi)算數(shù)運(yùn)算的結(jié)果
$ + 中括號(hào):$[]
$[]的功能與$(())一樣,都是用于算術(shù)運(yùn)算echo "20 + 5 * 6 = $[20 + 5 * 6]" ------------------------- 20 + 5 * 6 = 50
$ + 大括號(hào):${}
${}的功能是變量引用,類似于$符,但是${}比$的替換范圍更精準(zhǔn)
小括號(hào):
()用來(lái)定義一個(gè)數(shù)組變量
雙小括號(hào):
(())雙小括號(hào)命令允許在比較過(guò)程中使用高級(jí)數(shù)學(xué)表達(dá)式
中括號(hào):
[]單個(gè)的中括號(hào)的功能與
test命令一樣,都是用作條件測(cè)試
雙中括號(hào):
[[]]雙中括號(hào)提供了針對(duì)字符串比較的高級(jí)特性,使用雙中括號(hào)
[[]]進(jìn)行字符串比較時(shí),可以把右邊的項(xiàng)看做一個(gè)模式,故而可以在[[]]中使用正則表達(dá)式
大括號(hào):
{}大括號(hào)用于括起一個(gè)語(yǔ)句塊
冒號(hào):
(:)作為內(nèi)建命令:占位符、參數(shù)擴(kuò)展和重定向
Shell里面的括號(hào)
${a}:變量a的值, 在不引起歧義的情況下可以省略大括號(hào)$(cmd):命令替換, 和cmd效果相同$((exp)):增強(qiáng)括號(hào)的用法和expr exp效果相同,計(jì)算數(shù)學(xué)表達(dá)式exp的數(shù)值。其中exp只要符合C語(yǔ)言的運(yùn)算規(guī)則即可,甚至三目運(yùn)算符和邏輯表達(dá)式都可以計(jì)算。可以省略$例如:
for((i=0;i<5;i++)) # 如果不使用雙括號(hào) for i in seq 0 4 for i in {0..4}if (($i<5)) # 如果不使用雙括號(hào) if [ $i -lt 5 ]
expr命令:是一款表達(dá)式計(jì)算工具,使用它完成表達(dá)式的求值操作
expr 1 + 2 + 3 - 4 ------------------------- 2語(yǔ)法要求,中間的空格必須加
eval命令:對(duì)后面的
cmdLine進(jìn)行兩遍掃描,如果第一遍掃描后,cmdLine是個(gè)普通命令,則執(zhí)行此命令;如果cmdLine中含有變量的間接引用,則保證間接引用的語(yǔ)義
type命令:顯示命令屬性,會(huì)顯示該命令所在的位置
type [-aftpP] name [name,...]
-a:打印name的所有可能情況-f:不會(huì)去查找function-t:打印alias、keyword、function、built-in、file這五種類型-p:如果type -t name輸出file,那么會(huì)打印name所在路徑-P:不管type -t name是不是輸出file,都會(huì)去搜索name所在路徑。例如:type -P ls,盡管type -t ls打印的是alias(因?yàn)?code>alias的優(yōu)先級(jí)高于file),但是仍然會(huì)搜索出ls所在的路徑/bin/lstype -a ls ------------------------- ls is an alias for ls -G ls is /bin/ls如果
type不加任何選項(xiàng),直接加一個(gè)或者多個(gè)name,那么會(huì)依次打印這些name的類型。只有所有name的類型都能成功打印,type才返回成功。否則,只要任何一個(gè)name類型無(wú)法打印,那么就返回失敗
echo命令:按照規(guī)則打印字符串
echo [-ne][字符串]
-n:不要在最后自動(dòng)換行-e:若字符串中出現(xiàn)以下字符,則特別加以處理:\a:發(fā)出警告;\b:刪除前一個(gè)字符;\c:不產(chǎn)生進(jìn)一步輸出(\c后面的字符不會(huì)輸出);\f:換行但光標(biāo)仍舊停留在原來(lái)的位置;\n:換行且光標(biāo)移至行首;\r:光標(biāo)移至行首,但不換行;\t:插入tab;\v:與\f相同;\\:插入\字符;\nnn:插入nnn(八進(jìn)制)所代表的ASCII字符;用
echo命令打印帶有色彩的文字:
- 文字色:
echo -e "\e[1;31mThis is red text\e[0m"
\e[1;31m:將顏色設(shè)置為紅色
\e[0m:將顏色重新置回
顏色碼:重置=0,黑色=30,紅色=31,綠色=32,黃色=33,藍(lán)色=34,洋紅=35,青色=36,白色=37- 背景色:
echo -e "\e[1;42mGreed Background\e[0m"
顏色碼:重置=0,黑色=40,紅色=41,綠色=42,黃色=43,藍(lán)色=44,洋紅=45,青色=46,白色=47- 文字閃動(dòng):
echo -e "\033[37;31;5mLogic Cat 帥帥帥...\033[39;49;0m"
紅色數(shù)字處還有其他數(shù)字參數(shù):0關(guān)閉所有屬性、1設(shè)置高亮度(加粗)、4下劃線、5閃爍、7反顯、8消隱
grep命令:用于查找文件里符合條件的字符串
創(chuàng)建
Common Symbol目錄,Common Symbol目錄下創(chuàng)建test.m文件,寫入以下代碼:#import <Foundation/Foundation.h> void SomeNewFunction_weak_import(void) __attribute__((weak_import)); void SomeNewFunction_weak_import(void) { NSLog(@"SomeNewFunction_weak_import"); } void SomeNewFunction_weak(void) __attribute__((weak)); void SomeNewFunction_weak(void) { NSLog(@"SomeNewFunction_weak"); }在
test.m文件中,搜索weak字符串
grep "$KEY_WORD" --color=auto -- $FILEgrep weak --color=auto -- ../Common\ Symbol/test.m ------------------------- void SomeNewFunction_weak_import(void) __attribute__((weak_import)); void SomeNewFunction_weak_import(void) { NSLog(@"SomeNewFunction_weak_import"); void SomeNewFunction_weak(void) __attribute__((weak)); void SomeNewFunction_weak(void) { NSLog(@"SomeNewFunction_weak");
-- ../Common\ Symbol/test.m:其中--表示當(dāng)前命令已經(jīng)沒(méi)有參數(shù)要添加了,后面的內(nèi)容都是傳遞給命令的- 可以通過(guò)
--的方式,將內(nèi)容和參數(shù)區(qū)分開(kāi)路徑中包含空格,則有三種不同的解決策略:
- 加
\轉(zhuǎn)義grep weak --color=auto -- ../Common\ Symbol/test.m
- 加雙引號(hào)
grep weak --color=auto -- "../Common Symbol/test.m"
- 加單引號(hào)
grep weak --color=auto -- '../Common Symbol/test.m'錯(cuò)誤寫法:
grep weak --color=auto -- "../Common\ Symbol/test.m" grep weak --color=auto -- '../Common\ Symbol/test.m' ------------------------- grep: ../Common\ Symbol/test.m: No such file or directory
- 使用雙引號(hào)或單引號(hào),里面不能再加
\轉(zhuǎn)義
標(biāo)準(zhǔn)輸出 & 輸入 & 錯(cuò)誤輸出
標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出可以將內(nèi)容重定向輸出到指定的設(shè)備(如打印機(jī))或文件中,標(biāo)準(zhǔn)輸入可以使用文件或其他輸入替換手動(dòng)輸入。
標(biāo)準(zhǔn)輸出(
stdout):代碼為1,使用>或>>使用
>或1>以覆蓋的方式,將正確的數(shù)據(jù)輸出到指定到文件或設(shè)備echo "LGCat" > Cat echo "LGCat123" > Cat
- 目錄下生成
Cat文件,只會(huì)記錄最后輸出的LGCat123使用
>>或1>>以累加到方式,將正確到數(shù)據(jù)輸出到指定到文件或者設(shè)備上echo "LGCat" >> Cat1 echo "LGCat123" >> Cat1
- 目錄下生成
Cat1文件,將兩次輸出內(nèi)容累加記錄
標(biāo)準(zhǔn)錯(cuò)誤輸出(
stderr):代碼為2,使用2>或2>>使用
2>以覆蓋的方式,將錯(cuò)誤的數(shù)據(jù)輸出到指定到文件或設(shè)備echo "LGCat" 2> Cat使用
2>>以累加的方式,將錯(cuò)誤的數(shù)據(jù)輸出到指定到文件或設(shè)備echo "LGCat" 2>> Cat1
標(biāo)準(zhǔn)輸入(
stdin):代碼為0,使用<或<<使用
<標(biāo)準(zhǔn)輸入cat < Cat ------------------------- LGCat123使用
cat > file或cat >> file標(biāo)準(zhǔn)輸入cat > Cat1237 111 222
- 使用
> file等待輸入,將輸入的內(nèi)容保存到file中,使用control + d結(jié)束輸入。>覆蓋>>累加使用
<<結(jié)束輸入,后接一個(gè)結(jié)束輸入符cat > Cat1237 << "cat" 111 222 cat
- 將
cat作為結(jié)結(jié)束提示符- 按照日常規(guī)范建議使用
eof表示結(jié)束提示符
單箭頭和雙箭頭的區(qū)別:
對(duì)于輸出:
- 單箭頭:當(dāng)指定的文件不存在時(shí),創(chuàng)建新文件寫入數(shù)據(jù);當(dāng)文件存在時(shí),清空原文件的內(nèi)容寫入數(shù)據(jù)
- 雙箭頭:當(dāng)指定的文件不存在時(shí),創(chuàng)建新文件寫入數(shù)據(jù);當(dāng)文件存在時(shí),在原件內(nèi)容的最后追加寫入數(shù)據(jù)
對(duì)于輸入:
- 單箭頭:將文件或其他輸入作為標(biāo)準(zhǔn)輸入(
<的左邊必須是命令,<右邊的輸入內(nèi)容作為命令的輸入)- 雙箭頭:結(jié)束輸入
將標(biāo)準(zhǔn)輸出和錯(cuò)誤輸出重定向到一個(gè)文件上:
將
stdin和stderr無(wú)序輸出到one.log:grep "Cat" file.log > one.log 2>one.log將
stdin和stderr序有輸出到one.log:grep "Cat" file.log > one.log 2>&1
- 首先
stdin重定向到one.log,然后使用2>&1表示stderr重定向至stdin,stderr在stdin之后輸入到one.log中簡(jiǎn)寫:
grep "Cat" file.log &> one.log
使用
>/dev/null將錯(cuò)誤的數(shù)據(jù)丟棄,只顯示正確的數(shù)據(jù)echo "123" > /dev/null
/dev/null代表linux的空設(shè)備文件,所有往這個(gè)文件里面寫入的內(nèi)容都會(huì)丟失,俗稱“黑洞”使用
&>或者>&將正確的數(shù)據(jù)和錯(cuò)誤的數(shù)據(jù)寫入同一個(gè)文件echo "111" &> Cat echo "222" >& Cat使用
1>&2正確返回值傳遞給2輸出通道,&2表示2輸出通道echo "111222" 1>&2使用
2>&1錯(cuò)誤返回值傳遞給1輸出通道,&1表示1輸出通道echo "111222" 2>&1
cmd;cmd不考慮命令相關(guān)性,連續(xù)執(zhí)行。echo "Cat1";echo "Cat2" ------------------------- Cat1 Cat2當(dāng)前一個(gè)命令執(zhí)行成功會(huì)回傳一個(gè)
$?=0的值e ------------------------- zsh: command not found: e ------------------------- echo $? ------------------------- 127
cmd1 && cmd2如果第一個(gè)命令的$?為0,則執(zhí)行第二個(gè)命令echo "Cat1" && echo "Cat2" ------------------------- Cat1 Cat2
cmd1 || cmd2如果第一個(gè)命令的$?為0,則不執(zhí)行第二個(gè)命令。否則執(zhí)行第二個(gè)命令e || echo "Cat" ------------------------- zsh: command not found: e Cat
|:管道僅能處理前面一個(gè)命令傳來(lái)的正確信息,將正確信息作為stdin傳給下一個(gè)命令echo "test.m" | grep weak
- 管道命令只處理前一個(gè)命令正確輸出,不處理錯(cuò)誤輸出
- 管道命令右邊命令,必須能夠接收標(biāo)準(zhǔn)輸入流命令才行
- 大多數(shù)命令都不接受標(biāo)準(zhǔn)輸入作為參數(shù),只能直接在命令行輸入?yún)?shù),這導(dǎo)致無(wú)法用管道命令傳遞參數(shù)
xargs:是將標(biāo)準(zhǔn)輸入轉(zhuǎn)為命令行參數(shù)echo "Cat1237" | xargs cat ------------------------- 111 222
-:減號(hào)在一些命令中表示從標(biāo)準(zhǔn)輸入(stdin)中獲取內(nèi)容echo "Cat1237" | xargs cat - ------------------------- 111 222
三種運(yùn)行方式
sh:
- 使用
$sh script.sh執(zhí)行腳本時(shí),當(dāng)前Shell是父進(jìn)程,生成一個(gè)子Shell進(jìn)程,在子Shell中執(zhí)行腳本- 腳本執(zhí)行完畢,退出子
Shell,回到當(dāng)前Shell。$./script.sh與$sh script.sh等效。也叫fork方式
source:
- 使用
$source script.sh方式,在當(dāng)前上下文中執(zhí)行腳本,不會(huì)生成新的進(jìn)程。腳本執(zhí)行完畢,回到當(dāng)前Shell$sh script.sh與$source script.sh等效。不需要有"執(zhí)行權(quán)限"
exec:
- 使用
exec ./scriptsh方式,會(huì)用command進(jìn)程替換當(dāng)前Shell進(jìn)程,并且保持pid不變- 執(zhí)行完畢,直接退出,不回到之前的
Shell環(huán)境
執(zhí)行權(quán)限
sh/bash/zsh:不需要執(zhí)行權(quán)限./script.sh:需要執(zhí)行權(quán)限source script.sh:不需要執(zhí)行權(quán)限exec:需要執(zhí)行權(quán)限
變量的定義
Shell變量默認(rèn)為字符串。Shell不關(guān)心這個(gè)串是什么含義declare a=3 b=4 c c=a+b echo $c ------------------------- a+b
Shell默認(rèn)的數(shù)值運(yùn)算是整數(shù)類型。所以若要進(jìn)行數(shù)學(xué)運(yùn)算,必須使用一些命令,例如:declare、expr、雙括號(hào)等declare a=`expr 3 + 4` b=$((1+1)) echo $a;echo $b ------------------------- 7 2
Shell變量可分為兩類:
- 局部變量:只在創(chuàng)建它們的
Shell中可用。在函數(shù)內(nèi)定義,函數(shù)執(zhí)行后就被刪除- 環(huán)境變量:可以在創(chuàng)建它們的
Shell及其派生出來(lái)的任意子進(jìn)程中使用。在整個(gè)腳本執(zhí)行期間,只要沒(méi)有被刪除就一直存在export a=3 echo $a ------------------------- 3
定義規(guī)則:
- 變量名必須以字母或下劃線字符開(kāi)頭,其余的字符可以是字母、數(shù)字(
0~9)或下劃線字符。任何其他的字符都標(biāo)志著變量名的終止- 大小寫敏感
- 給變量賦值時(shí),等號(hào)周圍不能有任何空白符
- 通常大寫字符為系統(tǒng)默認(rèn)變量。個(gè)人習(xí)慣
set:查看所有變量(含環(huán)境變量與自定義變量),以及設(shè)置Shell變量的新變量值
-a:標(biāo)示已修改的變量,以供輸出至環(huán)境變量-b:使被中止的后臺(tái)程序立刻回報(bào)執(zhí)行狀態(tài)-e:若指令傳回值不等于0,則立即退出Shell-f:取消使用通配符-h:自動(dòng)記錄函數(shù)的所在位置-H Shell:可利用!加<指令編號(hào)>的方式來(lái)執(zhí)行history中記錄的指令-k:指令所給的參數(shù)都會(huì)被視為此指令的環(huán)境變量-l:記錄for循環(huán)的變量名稱-m:使用監(jiān)視模式-n:只讀取指令,而不實(shí)際執(zhí)行-p:?jiǎn)?dòng)優(yōu)先順序模式-P:?jiǎn)?dòng)-P參數(shù)后,執(zhí)行指令時(shí),會(huì)以實(shí)際的文件或目錄來(lái)取代符號(hào)連接-t:執(zhí)行完隨后的指令,即退出Shell-u:當(dāng)執(zhí)行時(shí)使用到未定義過(guò)的變量,則顯示錯(cuò)誤信息-v:顯示Shell所讀取的輸入值-x:執(zhí)行指令后,會(huì)先顯示該指令及所下的參數(shù)set 11 22 33 44 echo $1 echo "$#" echo "$@" eval echo "\$$#" ------------------------- 11 4 11 22 33 44 44
declare/typeset [-aixrp]變量
-a:將變量定義成數(shù)組-i:將變量定義成整數(shù)-x:將變量定義成環(huán)境變量-r:將變量定義成readonly-p:顯示變量定義的方式和值+:取消變量屬性,但是+a和+r無(wú)效,無(wú)法刪除數(shù)組和只讀屬性,可以使用unset刪除數(shù)組,但是unset不能刪除只讀變量declare -i a=3 b=4 c c=a+b echo $c ------------------------- 7declare -p a ------------------------- typeset -i a=3
local關(guān)鍵字,用來(lái)在作用域內(nèi)創(chuàng)建變量,出了作用域被銷毀
Shell中定義的變量,默認(rèn)都是全局變量,即使在函數(shù)體中定義,外部也可以訪問(wèn)。如果想定義僅供函數(shù)體中可訪問(wèn)的本地變量,需要加上local關(guān)鍵字function DoWork { local LG_CAT="LG_Cat" return 0 }
export為Shell變量或函數(shù)設(shè)置導(dǎo)出屬性,成為環(huán)境變量。無(wú)法對(duì)未定義的函數(shù)添加導(dǎo)出屬性。同時(shí),重要的一點(diǎn)是,export的效力僅及于該次登陸操作。注銷或者重新開(kāi)一個(gè)窗口,export命令給出的環(huán)境變量都不存在了
-f:代表[變量名稱]為函數(shù)名稱-n:刪除變量的導(dǎo)出屬性。變量實(shí)際上并未刪除,只是不會(huì)輸出到后續(xù)指令的執(zhí)行環(huán)境中-p:顯示全部擁有導(dǎo)出屬性的變量-pf:顯示全部擁有導(dǎo)出屬性的函數(shù)-nf:刪除函數(shù)的導(dǎo)出屬性--:在它之后的選項(xiàng)無(wú)效
通配符
*:匹配任意字符串,包括空字符串,不包含對(duì)/字符的匹配。?:匹配任意單個(gè)字符,不能匹配/字符。[abc]:匹配a或者b或者c字符。[^abc]:不匹配a或者b或者c字符。[a-z]:匹配26個(gè)英文小寫字符中任意一個(gè)echo * ------------------------- Cat Cat1 Cat1237
用
set命令可以查看所有的變量
unset var命令可以清除變量var,var相當(dāng)于沒(méi)有定義過(guò)
readonly var可以把var變?yōu)橹蛔x變量,定義之后不能對(duì)var進(jìn)行任何更改
函數(shù)的聲明
函數(shù)的聲明形式:
- 有
funtion,可以不寫()。沒(méi)有function,必須寫()- 函數(shù)名和
{之間必須有空格- 不得聲明形式參數(shù)
- 必須在調(diào)用函數(shù)地方之前,聲明函數(shù)
- 無(wú)法重載
- 后來(lái)的聲明會(huì)覆蓋之前的聲明
- 沒(méi)有返回值的函數(shù),默認(rèn)返回函數(shù)內(nèi)最后一條指令的返回值。有返回值的函數(shù),只能返回整數(shù)
- 需要獲得函數(shù)值,只能通過(guò)
$?獲得。通過(guò)=獲得是空值有
funtion,可以不寫()function 函數(shù)名 { 函數(shù)體 }沒(méi)有
function,必須寫()函數(shù)名() { 函數(shù)體 }完整寫法
function 函數(shù)名() { 函數(shù)體 }案例:
function DoWork { LG_CAT="LG_Cat" echo "logic" return 2 } DoWork echo "$?" echo `DoWork` echo "$?" ------------------------- logic 2 logic 0
可以將
Shell中函數(shù),看作是定義一個(gè)新的命令,因此各個(gè)輸入?yún)?shù)直接用空格分隔。命令里面獲得參數(shù)方法可以通過(guò):$0...$n得到。$0代表函數(shù)本身
$#:傳入的參數(shù)的個(gè)數(shù)$*:所有的位置參數(shù)(作為單個(gè)字符串)$@:所有的位置參數(shù)(每個(gè)都作為獨(dú)立的字符串)$?:當(dāng)前Shell進(jìn)程中,上一個(gè)命令的返回值,如果上一個(gè)命令成功執(zhí)行則$?的值為0,否則為其他非零值$$:當(dāng)前Shell進(jìn)程的pid$!:后臺(tái)運(yùn)行的最后一個(gè)進(jìn)程的pid$-:顯示Shell使用的當(dāng)前選項(xiàng)$_:之前命令的最后一個(gè)參數(shù)function DoWork { echo "特殊變量:\n \$#:$#\\n \$0:$0\\n \$1:$1\\n \$2:$2\\n \$*:$*\\n \$@:$@\\n \$$:$$\\n \$-:$-\\n \$_:$_ " return 2 } DoWork "Cat" "LGCat" ------------------------- 特殊變量: $#:2 $0:DoWork $1:Cat $2:LGCat $*:Cat LGCat $@:Cat LGCat $$:70639 $-:569JNRXZghiklm $_:LGCat
參數(shù)擴(kuò)展
通過(guò)符號(hào)$獲得參數(shù)中存儲(chǔ)的值
間接參數(shù)擴(kuò)展:
${parameter-string}:當(dāng)parameter未設(shè)置則替換成string,不更改parameter值。否則,不做處理${parameter=string}:當(dāng)parameter未設(shè)置則替換成string,更改parameter值。否則,不做處理${parameter?string}:當(dāng)parameter沒(méi)有設(shè)置,則把string輸出到標(biāo)準(zhǔn)錯(cuò)誤中。否則,不做處理${parameter+string}:當(dāng)parameter為空的時(shí)替換成string。否則,不做處理${!parameter}:執(zhí)行雙重替換bash,這意味著它接受parameter的字符串并將其用作變量名。zsh不支持使用
bash:declare attr=a a=b echo ${!attr} ------------------------- b兼容
bash和zsh:declare attr=a a=b eval echo "\$$attr" ------------------------- b
冒號(hào)后面跟
=、+、-、?(不能有空格):
${parameter:-string}:當(dāng)parameter未設(shè)置或者為空則替換成string,不更改parameter值${parameter:=string}:當(dāng)parameter未設(shè)置或者為空則替換成string,更改parameter值${parameter:?string}:若變量parameter不為空,則使用變量parameter的值。若為空,則把string輸出到標(biāo)準(zhǔn)錯(cuò)誤中,并從腳本中退出${parameter:+string}:當(dāng)parameter不為空的時(shí)替換成string。若為空時(shí)則不替換或者說(shuō)是替換空值
子串?dāng)U展:
${parameter:offset}和${parameter:offset:length}
- 從
offset位置開(kāi)始截取長(zhǎng)度為length的子串,如果沒(méi)有提供length,則是從offset開(kāi)始到結(jié)尾offset可以是負(fù)值,且必須與冒號(hào)有間隔或者用()包裹。開(kāi)始位置是從字符串末尾開(kāi)始算起,然后取長(zhǎng)度為length的子串。例如:-1代表是從最后一個(gè)字符開(kāi)始。parameter是@,也就是所有的位置參數(shù)時(shí),offset必須從1開(kāi)始
替換:
${parameter/pattern/string}、${parameter//pattern/string}、${parameter/pattern}和${parameter//pattern}
- 大小寫敏感
string為空時(shí),則相當(dāng)于將匹配的子串刪除。parameter之后如果是/,則只匹配遇到的第一個(gè)子串parameter之后如果是//,則匹配所有的子串
刪除:
${parameter#pattern}、${parameter##pattern}、${parameter%pattern}和${parameter%%pattern}
#是去掉左邊,%是去掉右邊- 單一符號(hào)是最小匹配,兩個(gè)符號(hào)是最大匹配
參數(shù)長(zhǎng)度:
${#parameter}
判斷
多分支語(yǔ)句判斷:
除最后一個(gè)分支外(這個(gè)分支可以是普通分支,也可以是
*)分支),其它的每個(gè)分支都必須以;;結(jié)尾。;;代表一個(gè)分支的結(jié)束,不寫的話會(huì)有語(yǔ)法錯(cuò)誤最后一個(gè)分支可以寫
;;,也可以不寫。因?yàn)闊o(wú)論如何,執(zhí)行到esac都會(huì)結(jié)束整個(gè)case in語(yǔ)句語(yǔ)法:
case $變量 in "第一個(gè)變量?jī)?nèi)容") 程序 ;; #結(jié)束 *) # 用來(lái)托底,沒(méi)有匹配到數(shù)據(jù) ;; esac案例:
case $LG_CAT in "cat") echo "名字為cat" ;; "LGCat") echo "名字為L(zhǎng)GCat" ;; *) echo "未找到名字" ;; esac
[]:判斷符號(hào),兩個(gè)等號(hào)和一個(gè)等號(hào),效果類似
- 中括號(hào)里面的每個(gè)組件都需要空格分隔
- 中括號(hào)的變量,使用雙引號(hào)
- 中括號(hào)的常量,使用單引號(hào)或雙引號(hào)
一個(gè)條件判斷:
if [ condation ]; then 成立 else 不成立 fi多條件判斷:
if [ condation ]; then 成立 elif [ condation ]; then 成立 else 不成立 fi案例:
function DoWork { return 2 } DoWork if [[ $? -ne 0 ]]; then echo "函數(shù)調(diào)用出錯(cuò)" fiLG_CAT=Cat if [[ "${LG_CAT}" == "Cat" ]]; then echo "${LG_CAT}" fi
test命令:
test n1 -eq n2:
-eq:相等-ne:不等-gt:大于-lt:小于-ge:大于等于-le:小于等于字符串判斷:
-z string:判斷string是否為為空,為空則為true-n string:判斷string是否非空,為空則為falsestring1 = string2:字符串是否相等,相等為truestring1 != string2:字符串是否不等,相等為false多重條件判斷:
-a:兩個(gè)條件同時(shí)成立,為true-o:兩個(gè)條件任何一個(gè)成立,為true!:反向文件類型判斷:
-e:文件名是否存在-f:該文件名是否存在且是否為文件-d:該名稱是否存在且為目錄-L:該名稱是否存在且是否為鏈接文件文件權(quán)限檢測(cè):
-r:是否存在是否有可讀權(quán)限-w:是否存在是否有可寫權(quán)限-x:是否存在是否有可執(zhí)行權(quán)限-s:是否存在且為非空白文件兩文件比較
-nt:文件1是否比文件2新-ot:文件1是否比文件2舊-ef:文件1和文件2是否為同一個(gè)文件if [[ -e "./test與判斷.sh" ]]; then echo "文件存在" else echo "文件不存在" fi
判斷中沒(méi)有函數(shù)體會(huì)報(bào)錯(cuò),可以使用
:占位if [ true ]; then : fi
循環(huán)
當(dāng)條件成立,就進(jìn)行循環(huán):
while [ condation ] #判斷條件 do #循環(huán)開(kāi)始 程序 done #循環(huán)結(jié)束案例:
COUNTER=0 while [ $COUNTER -lt 5 ] do echo $COUNTER COUNTER=`expr $COUNTER + 1` done
當(dāng)條件成立,就終止循環(huán):
until [ condation ] #判斷條件 do #循環(huán)開(kāi)始 程序 done #循環(huán)結(jié)束案例:
a=0 until [ ! $a -lt 10 ] do echo $a a=`expr $a + 1` done
按照指定次數(shù)循環(huán):
for var in con1 con2 con3 ... do 程序 donefor (( 初始值; 限制值; 執(zhí)行步長(zhǎng) )) do 程序 done案例:
for loop in 1 2 3 4 5 do echo "The value is: $loop" donefor (( i = 1; i <= 5; i++ )) do echo "i=$i" done
總結(jié):
如何學(xué)習(xí)
Shell
- 學(xué)語(yǔ)法
- 看腳本
- 抄
常用命令參考
Shell有兩種方式
- 交互式(
Interactive)- 批處理(
Batch)方式
.bashrc、.bash_profile和.zshrc作用與區(qū)別
.bashrc、.bash_profile是給bash來(lái)使用的.zshrc是給zsh來(lái)使用的交互式登錄和非登錄
Shell
- 交互式登錄
Shell:bash會(huì)先查找/etc/profile文件,如果該文件存在,它將運(yùn)行文件中列出的命令。然后搜索~/.bash_profile、~/.bash_login以及~/.profile文件,順序讀取- 非登錄
Shell:讀取~/.bashrc三種運(yùn)行方式
sh:生成一個(gè)子Shell進(jìn)程source:不會(huì)生成新的進(jìn)程exec:用command進(jìn)程替換當(dāng)前Shell進(jìn)程執(zhí)行權(quán)限
sh/bash/zsh:不需要執(zhí)行權(quán)限./script.sh:需要執(zhí)行權(quán)限source script.sh:不需要執(zhí)行權(quán)限exec:需要執(zhí)行權(quán)限
