GUI(Graphical User Interface 圖形用戶界面)伪窖;
CLI(command-line interface别威,命令行界面)炸站;
shell不單單是一種CLI。它是一個時刻都運行的復(fù)制交互式程序沪铭。輸入命令并利用shell來運行腳本會出現(xià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伦意。不過由于bash shell的廣為流傳,很少有人使用其他的shell作為默認(rèn)的shell硼补。
默認(rèn)的交互shell會在用戶登錄某個虛擬控制臺終端或者GUI運行中運行終端仿真器時啟動驮肉。不過還有另外一個默認(rèn)的shell 是/bin/sh,它作為默認(rèn)的系統(tǒng)shell,用于那些需要在啟動時使用的系統(tǒng)shell腳本已骇。
ls -l /bin/sh //能看出 當(dāng)前默認(rèn)的shell是否被軟連接將默認(rèn)系統(tǒng)設(shè)置為了其他類型的shell离钝。
并不是必須要一直使用默認(rèn)的交互shell .可以使用發(fā)行版中所有的可以的shell,只需要輸入對應(yīng)的文件名票编。eg:
/bin/csh //就進(jìn)入了該shell 可以輸入exit來退出。
2. shell的父子關(guān)系
用于登錄某個虛擬控制器終端或在GUI中運行終端仿真器時所啟動的默認(rèn)的交互shell,是一個父級shell卵渴。
在CLI提示符后面輸入/bin/bash命令或在其他等效的bash命令時慧域,會創(chuàng)建一個新的shell程序。這個shell程序被稱為子shell浪读。子shell也擁有CLI提示符昔榴,同樣會等待命令輸入。
我們在輸入一個bash之后一個子shell就出現(xiàn)了碘橘。我們可以通過PPID 進(jìn)程ID來判斷父子關(guān)系互订。
對應(yīng)bash命令的參數(shù) 我們可以通過man bash查看。bash --help命令也可以提供額外的幫助痘拆。
我們可以通過exit來退出shell仰禽。
就算是不使用bash命令或者運行shell腳本 也可生成子shell。一種方法就算使用進(jìn)程列表纺蛆。
3. 進(jìn)程列表
你可以在一行中指定要依次運行的一系列命令吐葵。你可以通過命令列表來實現(xiàn),只需要在命令之間加入(;)即可桥氏。
pwd ; ls ; cd /etc
上面的例子温峭,所有的命令按照順序執(zhí)行,不存在任何問題字支。不過喲這并不是進(jìn)程列表诚镰。要成為進(jìn)程列表,這些命令需要包含在括號里面祥款。
(pwd ; ls ; cd /etc)
二者執(zhí)行結(jié)果看起來沒什么不同清笨,但起到的效果確是非同尋常。括號的加入使命令列表變成了進(jìn)程列表刃跛。生成了一個子shell來執(zhí)行對應(yīng)的命令抠艾。
說明進(jìn)程列表是一種命令分組。
還有一種命令分組是將命令放在花括號中桨昙,并在命令列表的尾部加上分號检号。語法為{command;}。使用這種方式進(jìn)行分組蛙酪,并不會創(chuàng)建出子shell齐苛。
要知道是否生成了子shell 可以借助一個環(huán)境變量$BASH_SUBSHELL。如果為0 表示沒有子shell,為1表示有桂塞。
在shell腳本中凹蜂,經(jīng)常使用子shell來進(jìn)行多進(jìn)程處理,但是采用子shell的成本不菲,會明顯拖慢處理速度玛痊。
子shell同樣存在問題汰瘫。它并非真正的多進(jìn)程處理,因為終端控制著子shell的I/O擂煞。
4. 別出心裁的子shell用法
在交互式的shell CLI中混弥,還有很多更富有成效的子shell用法。進(jìn)程列表对省、協(xié)程和管道都利用了子shell蝗拿。它們都可以有效地在交互式shell中使用。 在交互式shell中蒿涎,一個高效的子shell用法就是使用后臺模式哀托。在討論如何將后臺模式與子shell搭配使用之前,你得先搞明白什么是后臺模式同仆。
4.1 后臺模式
在后臺模式中運行命令可以在處理命令的同時讓出CLI,以供他用裙品。演示后臺模式的一個經(jīng)典命令就是sleep 俗批。 sleep 命令接受一個參數(shù),該參數(shù)是你希望進(jìn)程等待(睡眠)的秒數(shù)市怎。這個命令在腳本中常用于引入一段時間的暫停岁忘。命令sleep 10 會將會話暫停10秒鐘,然后返回shell CLI提示符区匠。
sleep 10
要想將命令置入后臺模式干像,可以在命令末尾加上字符& 。把sleep命令置入后臺模式可以讓我們利用ps 命令來小窺一番驰弄。
sleep 10&
ps -f
//也可以使用jobs命令來顯示當(dāng)前運行在后臺模式中的所有用戶的進(jìn)程(作業(yè))
jobs
5. 外部命令
有時候也被稱為文件系統(tǒng)命令麻汰,是存在bash shell之外的的程序。它們并不是shell程序的一部分戚篙。外部命令通常位于/bin,/usr/bin,/sbin,/user/sbin中五鲫。
ps就是一個外部命令。你可以使用which和type命令找到它岔擂。
當(dāng)外部命令執(zhí)行時位喂,會創(chuàng)建一個子進(jìn)程。這種操作被稱為衍生乱灵。當(dāng)進(jìn)程必須執(zhí)行衍生操作時塑崖,它需要花費時間和精力來設(shè)置新子進(jìn)程的環(huán)境,所以外包命令多少還是有代價的痛倚。
6. 內(nèi)建命令
內(nèi)建與外部命令的區(qū)別在于前者不需要使用子進(jìn)程來執(zhí)行规婆。它們已經(jīng)和shell編譯稱為一體。和外部命令的區(qū)別在于前者不需要使用子進(jìn)程來執(zhí)行。它們已經(jīng)和shell編譯成了一體聋呢,作為shell工具的組成部分存在苗踪。不需要借助外部程序文件來運行。
cd 和 exit 命令都內(nèi)建于bash shell削锰⊥ú可以利用type 命令來了解某個命令是否是內(nèi)建的。
type exit // type is a shell builtin
type cd //cd is a shell builtin
因為既不需要通過衍生出子進(jìn)程來執(zhí)行器贩,也不需要打開程序文件颅夺,內(nèi)建命令的執(zhí)行速度要更快,效率也更高蛹稍。吧黄。 要注意,有些命令有多種實現(xiàn)唆姐。例如echo 和 pwd 既有內(nèi)建命令也有外部命令拗慨。兩種實現(xiàn)略有不同。要查看命令的不同實現(xiàn)奉芦,使用type 命令的-a 選項赵抢。
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命令
一個有用的內(nèi)建命令是history 命令。bash shell會跟蹤你用過的命令声功。你可以喚回這些命令并重新使用烦却。
要查看最近用過的命令列表,可以輸入不帶選項的history 命令先巴。
history //一般會保留1000條
你可以設(shè)置保存在bash歷史記錄中的命令數(shù)其爵。要想實現(xiàn)這一點,你需要修改名為HISTSIZE 的環(huán)境變量伸蚯。
你可以喚回并重用歷史列表中最近的命令摩渺。這樣能夠節(jié)省時間和擊鍵量。 輸入!! 剂邮,然后按回車鍵就能夠喚出剛剛用過的那條命令來使用证逻。
當(dāng)輸入!! 時,bash首先會顯示出從shell的歷史記錄中喚回的命令抗斤。然后執(zhí)行該命令囚企。
命令歷史記錄被保存在隱藏文件.bash_history中,它位于用戶的主目錄中瑞眼。
cat .bash_history
這里要注意的是龙宏,bash命令的歷史記錄是先存放在內(nèi)存中,當(dāng)shell退出時才被寫入到歷史文件中伤疙。
還有一些強制往歷史文件里面插入記錄 history -a
強制重新讀取歷史文件histoty -n
(mac終端執(zhí)行無效银酗,對個會話終端打開的時候辆影,使用該命令,強制重新讀取文件中的記錄)
!10349
喚回歷史記錄中的命令黍特,只需要感嘆號加上歷史列表中的編號即可蛙讥。
6.2 命名別名
alias 命令是另一個shell的內(nèi)建命令。命令別名允許你為常用的命令(及其參數(shù))創(chuàng)建另一個名稱灭衷,從而將輸入量減少到最低次慢。 你所使用的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'
在定義好別名之后迫像,你隨時都可以在shell中使用它,就算在shell腳本中也沒問題瞳遍。要注意闻妓,因為命令別名屬于內(nèi)部命令,一個別名僅在它所被定義的shell進(jìn)程中才有效掠械。這樣相當(dāng)于我只能在我當(dāng)前打開的進(jìn)程中使用由缆,而不能在其他進(jìn)程使用,很有局限性猾蒂。
刪除重命名
unalias gs
若要每次登入都能夠使用這些命令別名均唉,則可將相應(yīng)的alias命令存放到bash的初始化文件/etc/bashrc中。