理解shell

GUI(Graphical User Interface 圖形用戶界面);
CLI(command-line interface,命令行界面);

shell不單單是一種CLI。它是一個(gè)時(shí)刻都運(yùn)行的復(fù)制交互式程序。輸入命令并利用shell來(lái)運(yùn)行腳本會(huì)出現(xiàn)一些即有趣又令人困惑的問(wèn)題。搞清楚shell進(jìn)程以及它與系統(tǒng)之間的關(guān)系能夠幫助你解決這些難題。

1. shell的類型

ls -l /bin/bash
ls -l /bin/tcsh //源自最初的C shell
ls - l /bin/dash //ash shell的Debian版本
ls -l /bin.csh //C shell的軟連接指向的是tcsh shell

這些shell程序都可以被設(shè)置為用戶默認(rèn)的shell。不過(guò)由于bash shell的廣為流傳,很少有人使用其他的shell作為默認(rèn)的shell。

默認(rèn)的交互shell會(huì)在用戶登錄某個(gè)虛擬控制臺(tái)終端或者GUI運(yùn)行中運(yùn)行終端仿真器時(shí)啟動(dòng)。不過(guò)還有另外一個(gè)默認(rèn)的shell 是/bin/sh,它作為默認(rèn)的系統(tǒng)shell,用于那些需要在啟動(dòng)時(shí)使用的系統(tǒng)shell腳本。

ls -l  /bin/sh //能看出 當(dāng)前默認(rèn)的shell是否被軟連接將默認(rèn)系統(tǒng)設(shè)置為了其他類型的shell。

并不是必須要一直使用默認(rèn)的交互shell .可以使用發(fā)行版中所有的可以的shell,只需要輸入對(duì)應(yīng)的文件名。eg:

/bin/csh //就進(jìn)入了該shell 可以輸入exit來(lái)退出。

2. shell的父子關(guān)系

用于登錄某個(gè)虛擬控制器終端或在GUI中運(yùn)行終端仿真器時(shí)所啟動(dòng)的默認(rèn)的交互shell,是一個(gè)父級(jí)shell。
在CLI提示符后面輸入/bin/bash命令或在其他等效的bash命令時(shí),會(huì)創(chuàng)建一個(gè)新的shell程序。這個(gè)shell程序被稱為子shell。子shell也擁有CLI提示符,同樣會(huì)等待命令輸入。

bash
bash
exit

我們?cè)谳斎胍粋€(gè)bash之后一個(gè)子shell就出現(xiàn)了。我們可以通過(guò)PPID 進(jìn)程ID來(lái)判斷父子關(guān)系。

父子shell

對(duì)應(yīng)bash命令的參數(shù) 我們可以通過(guò)man bash查看。bash --help命令也可以提供額外的幫助。
我們可以通過(guò)exit來(lái)退出shell。

就算是不使用bash命令或者運(yùn)行shell腳本 也可生成子shell。一種方法就算使用進(jìn)程列表。

3. 進(jìn)程列表

你可以在一行中指定要依次運(yùn)行的一系列命令。你可以通過(guò)命令列表來(lái)實(shí)現(xiàn),只需要在命令之間加入(;)即可。

pwd ; ls ; cd /etc

上面的例子,所有的命令按照順序執(zhí)行,不存在任何問(wèn)題。不過(guò)喲這并不是進(jìn)程列表。要成為進(jìn)程列表,這些命令需要包含在括號(hào)里面。

(pwd ; ls ; cd /etc)

二者執(zhí)行結(jié)果看起來(lái)沒(méi)什么不同,但起到的效果確是非同尋常。括號(hào)的加入使命令列表變成了進(jìn)程列表。生成了一個(gè)子shell來(lái)執(zhí)行對(duì)應(yīng)的命令。

說(shuō)明進(jìn)程列表是一種命令分組
還有一種命令分組是將命令放在花括號(hào)中,并在命令列表的尾部加上分號(hào)。語(yǔ)法為{command;}。使用這種方式進(jìn)行分組,并不會(huì)創(chuàng)建出子shell。

BASH_SUBSHELL變量

要知道是否生成了子shell 可以借助一個(gè)環(huán)境變量$BASH_SUBSHELL。如果為0 表示沒(méi)有子shell,為1表示有。

在shell腳本中,經(jīng)常使用子shell來(lái)進(jìn)行多進(jìn)程處理,但是采用子shell的成本不菲,會(huì)明顯拖慢處理速度。
子shell同樣存在問(wèn)題。它并非真正的多進(jìn)程處理,因?yàn)榻K端控制著子shell的I/O。

4. 別出心裁的子shell用法

在交互式的shell CLI中,還有很多更富有成效的子shell用法。進(jìn)程列表、協(xié)程和管道都利用了子shell。它們都可以有效地在交互式shell中使用。 在交互式shell中,一個(gè)高效的子shell用法就是使用后臺(tái)模式。在討論如何將后臺(tái)模式與子shell搭配使用之前,你得先搞明白什么是后臺(tái)模式

4.1 后臺(tái)模式

在后臺(tái)模式中運(yùn)行命令可以在處理命令的同時(shí)讓出CLI,以供他用。演示后臺(tái)模式的一個(gè)經(jīng)典命令就是sleep 。 sleep 命令接受一個(gè)參數(shù),該參數(shù)是你希望進(jìn)程等待(睡眠)的秒數(shù)。這個(gè)命令在腳本中常用于引入一段時(shí)間的暫停。命令sleep 10 會(huì)將會(huì)話暫停10秒鐘,然后返回shell CLI提示符。

sleep 10

要想將命令置入后臺(tái)模式,可以在命令末尾加上字符& 。把sleep命令置入后臺(tái)模式可以讓我們利用ps 命令來(lái)小窺一番。

sleep 10&
ps -f 
//也可以使用jobs命令來(lái)顯示當(dāng)前運(yùn)行在后臺(tái)模式中的所有用戶的進(jìn)程(作業(yè))
jobs

5. 外部命令

有時(shí)候也被稱為文件系統(tǒng)命令,是存在bash shell之外的的程序。它們并不是shell程序的一部分。外部命令通常位于/bin,/usr/bin,/sbin,/user/sbin中。
ps就是一個(gè)外部命令。你可以使用which和type命令找到它。

當(dāng)外部命令執(zhí)行時(shí),會(huì)創(chuàng)建一個(gè)子進(jìn)程。這種操作被稱為衍生。當(dāng)進(jìn)程必須執(zhí)行衍生操作時(shí),它需要花費(fèi)時(shí)間和精力來(lái)設(shè)置新子進(jìn)程的環(huán)境,所以外包命令多少還是有代價(jià)的。

6. 內(nèi)建命令

內(nèi)建與外部命令的區(qū)別在于前者不需要使用子進(jìn)程來(lái)執(zhí)行。它們已經(jīng)和shell編譯稱為一體。和外部命令的區(qū)別在于前者不需要使用子進(jìn)程來(lái)執(zhí)行。它們已經(jīng)和shell編譯成了一體,作為shell工具的組成部分存在。不需要借助外部程序文件來(lái)運(yùn)行。

cd 和 exit 命令都內(nèi)建于bash shell。可以利用type 命令來(lái)了解某個(gè)命令是否是內(nèi)建的。

type exit // type is a shell builtin
type cd //cd is a shell builtin

因?yàn)榧炔恍枰ㄟ^(guò)衍生出子進(jìn)程來(lái)執(zhí)行,也不需要打開(kāi)程序文件,內(nèi)建命令的執(zhí)行速度要更快,效率也更高。。 要注意,有些命令有多種實(shí)現(xiàn)。例如echo 和 pwd 既有內(nèi)建命令也有外部命令。兩種實(shí)現(xiàn)略有不同。要查看命令的不同實(shí)現(xiàn),使用type 命令的-a 選項(xiàng)。


 type -a pwd
//pwd is a shell builtin
//pwd is /bin/pwd

 type -a echo
 //echo is a shell builtin
 //echo is /bin/echo

6.1 使用history命令
一個(gè)有用的內(nèi)建命令是history 命令。bash shell會(huì)跟蹤你用過(guò)的命令。你可以喚回這些命令并重新使用。

要查看最近用過(guò)的命令列表,可以輸入不帶選項(xiàng)的history 命令。

history //一般會(huì)保留1000條

你可以設(shè)置保存在bash歷史記錄中的命令數(shù)。要想實(shí)現(xiàn)這一點(diǎn),你需要修改名為HISTSIZE 的環(huán)境變量。

你可以喚回并重用歷史列表中最近的命令。這樣能夠節(jié)省時(shí)間和擊鍵量。 輸入!! ,然后按回車鍵就能夠喚出剛剛用過(guò)的那條命令來(lái)使用。

當(dāng)輸入!! 時(shí),bash首先會(huì)顯示出從shell的歷史記錄中喚回的命令。然后執(zhí)行該命令。

命令歷史記錄被保存在隱藏文件.bash_history中,它位于用戶的主目錄中。

cat .bash_history

這里要注意的是,bash命令的歷史記錄是先存放在內(nèi)存中,當(dāng)shell退出時(shí)才被寫(xiě)入到歷史文件中。

還有一些強(qiáng)制往歷史文件里面插入記錄 history -a
強(qiáng)制重新讀取歷史文件histoty -n (mac終端執(zhí)行無(wú)效,對(duì)個(gè)會(huì)話終端打開(kāi)的時(shí)候,使用該命令,強(qiáng)制重新讀取文件中的記錄)
!10349 喚回歷史記錄中的命令,只需要感嘆號(hào)加上歷史列表中的編號(hào)即可。

6.2 命名別名

alias 命令是另一個(gè)shell的內(nèi)建命令。命令別名允許你為常用的命令(及其參數(shù))創(chuàng)建另一個(gè)名稱,從而將輸入量減少到最低。 你所使用的Linux發(fā)行版很有可能已經(jīng)為你設(shè)置好了一些常用命令的別名。要查看當(dāng)前可用的別名,使用alias

alias

-='cd -'
...=../..
....=../../..
.....=../../../..
......=../../../../..
1='cd -'
2='cd -2'
3='cd -3'
4='cd -4'
5='cd -5'
6='cd -6'
7='cd -7'
8='cd -8'
9='cd -9'
_=sudo
afind='ack -il'
d='dirs -v | head -10'
g=git
ga='git add'
gaa='git add --all'
gapa='git add --patch'
gb='git branch'
gba='git branch -a'
gbd='git branch -d'
gbda='git branch --no-color --merged | command grep -vE "^(\*|\s*(master|develop|dev)\s*$)" | command xargs -n 1 git branch -d'
gbl='git blame -b -w'
gbnm='git branch --no-merged'
gbr='git branch --remote'
gbs='git bisect'
gbsb='git bisect bad'
gbsg='git bisect good'
gbsr='git bisect reset'
gbss='git bisect start'
gc='git commit -v'
'gc!'='git commit -v --amend'
gca='git commit -v -a'
'gca!'='git commit -v -a --amend'
gcam='git commit -a -m'
'gcan!'='git commit -v -a --no-edit --amend'
'gcans!'='git commit -v -a -s --no-edit --amend'
gcb='git checkout -b'
gcd='git checkout develop'
gcf='git config --list'
gcl='git clone --recursive'
gclean='git clean -fd'
gcm='git checkout master'
gcmsg='git commit -m'
'gcn!'='git commit -v --no-edit --amend'
gco='git checkout'
gcount='git shortlog -sn'
gcp='git cherry-pick'
gcpa='git cherry-pick --abort'
gcpc='git cherry-pick --continue'
gcs='git commit -S'
gd='git diff'
gdca='git diff --cached'
gdct='git describe --tags `git rev-list --tags --max-count=1`'
gdt='git diff-tree --no-commit-id --name-only -r'
gdw='git diff --word-diff'
gf='git fetch'
gfa='git fetch --all --prune'
gfo='git fetch origin'
gg='git gui citool'
gga='git gui citool --amend'
ggpull='git pull origin $(git_current_branch)'
ggpur=ggu
ggpush='git push origin $(git_current_branch)'
ggsup='git branch --set-upstream-to=origin/$(git_current_branch)'
ghh='git help'
gignore='git update-index --assume-unchanged'
gignored='git ls-files -v | grep "^[[:lower:]]"'
git-svn-dcommit-push='git svn dcommit && git push github master:svntrunk'
gk='\gitk --all --branches'
gke='\gitk --all $(git log -g --pretty=%h)'
gl='git pull'
glg='git log --stat'
glgg='git log --graph'
glgga='git log --graph --decorate --all'
glgm='git log --graph --max-count=10'
glgp='git log --stat -p'
glo='git log --oneline --decorate'
globurl='noglob urlglobber '
glog='git log --oneline --decorate --graph'
gloga='git log --oneline --decorate --graph --all'
glol='git log --graph --pretty='\''%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'\'' --abbrev-commit'
glola='git log --graph --pretty='\''%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'\'' --abbrev-commit --all'
glp=_git_log_prettily
glum='git pull upstream master'
gm='git merge'
gmom='git merge origin/master'
gmt='git mergetool --no-prompt'
gmtvim='git mergetool --no-prompt --tool=vimdiff'
gmum='git merge upstream/master'
gp='git push'
gpd='git push --dry-run'
gpoat='git push origin --all && git push origin --tags'
gpristine='git reset --hard && git clean -dfx'
gpsup='git push --set-upstream origin $(git_current_branch)'
gpu='git push upstream'
gpv='git push -v'
gr='git remote'
gra='git remote add'
grb='git rebase'
grba='git rebase --abort'
grbc='git rebase --continue'
grbi='git rebase -i'
grbm='git rebase master'
grbs='git rebase --skip'
grep='grep  --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn}'
grh='git reset HEAD'
grhh='git reset HEAD --hard'
grmv='git remote rename'
grrm='git remote remove'
grset='git remote set-url'
grt='cd $(git rev-parse --show-toplevel || echo ".")'
gru='git reset --'
grup='git remote update'
grv='git remote -v'
gsb='git status -sb'
gsd='git svn dcommit'
gsi='git submodule init'
gsps='git show --pretty=short --show-signature'
gsr='git svn rebase'
gss='git status -s'
gst='git status'
gsta='git stash save'
gstaa='git stash apply'
gstc='git stash clear'
gstd='git stash drop'
gstl='git stash list'
gstp='git stash pop'
gsts='git stash show --text'
gsu='git submodule update'
gts='git tag -s'
gtv='git tag | sort -V'
gunignore='git update-index --no-assume-unchanged'
gunwip='git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1'
gup='git pull --rebase'
gupv='git pull --rebase -v'
gwch='git whatchanged -p --abbrev-commit --pretty=medium'
gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit -m "--wip--"'
history='fc -l 1'
l='ls -lah'
la='ls -lAh'
ll='ls -lh'
ls='ls -G'
lsa='ls -lah'
md='mkdir -p'
please=sudo
po=popd
pu=pushd
rd=rmdir
run-help=man
which-command=whence

重命名

alias gs='git status'

在定義好別名之后,你隨時(shí)都可以在shell中使用它,就算在shell腳本中也沒(méi)問(wèn)題。要注意,因?yàn)槊顒e名屬于內(nèi)部命令,一個(gè)別名僅在它所被定義的shell進(jìn)程中才有效。這樣相當(dāng)于我只能在我當(dāng)前打開(kāi)的進(jìn)程中使用,而不能在其他進(jìn)程使用,很有局限性。

刪除重命名

unalias gs

若要每次登入都能夠使用這些命令別名,則可將相應(yīng)的alias命令存放到bash的初始化文件/etc/bashrc中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,494評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,283評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,953評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,714評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,410評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,940評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,776評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,210評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,642評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,878評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,654評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容