您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)Shell的本質(zhì)以及用法是怎樣的,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
要點(diǎn):命令行、標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出、重定向、管道、后臺(tái)運(yùn)行程序、kill:終止后臺(tái)作業(yè)、文件名生成/路徑名展開、內(nèi)置命令
Shell是用戶的系統(tǒng)界面,提供了用戶與內(nèi)核進(jìn)行交互操作的一種接口。它接收用戶輸入的命令并把它送去內(nèi)核執(zhí)行。實(shí)際上Shell是一個(gè)命令解釋器,它解釋由用戶輸入的命令并且把它們送到內(nèi)核。
當(dāng)在命令提示符后鍵入命令回車,shell將執(zhí)行相應(yīng)的程序。比如,鍵入ls后回車,shell開始執(zhí)行名為ls的工具。也可讓shell以同樣的方式執(zhí)行其他類型的程序,如shell腳本、應(yīng)用程序或自己編寫的程序。包含命令和參數(shù)的行稱為命令行。命令是指在命令行上鍵入的字符,同時(shí)還指對(duì)應(yīng)動(dòng)作所調(diào)用的程序。
命令行語(yǔ)法說明了行中各個(gè)元素的排列順序和間隔方式。當(dāng)用戶鍵入命令回車后,shell將掃描命令行進(jìn)行語(yǔ)法檢查。命令行上基本的語(yǔ)法格式如下:
command [arg1] ... [argn] RETURN
命令行上采用一個(gè)或多個(gè)空格來隔開每個(gè)元素。其中,command為命令的名字,arg1到argn為命令的參數(shù),回車是終止命令的按鍵。語(yǔ)法格式中的方括號(hào)表明被括起來的參數(shù)為可選項(xiàng)。并不是所有的命令都需要參數(shù),有些命令就沒有參數(shù),有些命令需要可變數(shù)目的參數(shù),有些命令則需要特定數(shù)目的參數(shù)。選項(xiàng)是一種特殊類型的參數(shù),前面通常為一個(gè)或兩個(gè)連字符(“-”或“--”)。
一些有用的Linux命令行僅由命令名組成而不帶任何參數(shù)。例如,不帶任何參數(shù)的ls將顯示工作目錄下的文件列表。多數(shù)命令都帶一個(gè)或多個(gè)參數(shù),當(dāng)使用需要帶參數(shù)的命令時(shí),若沒有帶參數(shù),或帶了不正確的參數(shù),或參數(shù)數(shù)目使用錯(cuò)誤,系統(tǒng)都會(huì)返回用戶簡(jiǎn)短錯(cuò)誤信息提示,這些信息稱為命令的用法消息(usage message)。
命令行上,每一串不含空格字符的字符序列稱為記號(hào)或字。參數(shù)是一種記號(hào),如文件名、文本串、數(shù)字或命令處理的其他對(duì)象。
下面展示一個(gè)cp的命令行:
[root@QUFENGBIN ~]# cp temp tempcopy
參數(shù)都有編號(hào),其中命令本身作為參數(shù)0,它是命令行參數(shù)的開始。在這個(gè)例子中,cp為參數(shù)0,temp為參數(shù)1,tempcopy為參數(shù)2。cp至少需要兩個(gè)字段(還可帶多個(gè)參數(shù),但不能少于兩個(gè)),參數(shù)1是已存在的文件名,參數(shù)2是cp要?jiǎng)?chuàng)建或重寫的文件。這兩個(gè)參數(shù)都不是可選的,而是命令運(yùn)行所必需的。 PS:shell一些關(guān)于參數(shù)的特殊字符 | 特殊字符 | 說明 |
---|---|---|
$$ | Shell本身的PID(ProcessID) | |
$! | Shell最后運(yùn)行的后臺(tái)Process的PID | |
$? | 最后運(yùn)行的命令的結(jié)束代碼(返回值) | |
$- | 使用Set命令設(shè)定的Flag一覽 | |
$* | 所有參數(shù)列表。如"$*"用「"」括起來的情況、以"$1 $2 … $n"的形式輸出所有參數(shù)。 | |
$@ | 所有參數(shù)列表。如"$@"用「"」括起來的情況、以"$1" "$2" … "$n" 的形式輸出所有參數(shù)。 | |
$# | 添加到Shell的參數(shù)個(gè)數(shù) | |
$0 | Shell本身的文件名 | |
$1~$n | 添加到Shell的各參數(shù)值。$1是第1參數(shù)、$2是第2參數(shù)…。 |
[root@aminglinux_01 test]# cat test.sh #!/bin/sh echo "number:$#" echo "scname:$0" echo "first :$1" echo "second:$2" echo "argume:$@" [root@aminglinux_01 test]# sh test.sh aa bb number:2 scname:test.sh first :aa second:bb argume:aa bb
選項(xiàng)(option)是改變命令執(zhí)行效果的參數(shù)。可通過指定多個(gè)選項(xiàng)使得命令按照不同的方式執(zhí)行。選項(xiàng)與特定的程序相關(guān),并由命令行上調(diào)用的程序解釋,而非由shell解釋。
按照約定,選項(xiàng)是跟在命令之后其他參數(shù)(如文件名)之前的單獨(dú)的參數(shù)。多數(shù)命令的選項(xiàng)前面需要加一個(gè)連字符,但這個(gè)要求是與工具相關(guān)的,而與shell無關(guān)。GNU程序的選項(xiàng)前通常帶兩個(gè)連字符。例如,--help會(huì)生成用法消息。
當(dāng)需要多個(gè)選項(xiàng)時(shí),可將多個(gè)單字符選項(xiàng)組合成一個(gè)參數(shù),以一個(gè)連字符開始,在選項(xiàng)前不要加空格。但是,這樣合并后的選項(xiàng)之前不能使用兩個(gè)連字符。對(duì)于合并選項(xiàng)的具體規(guī)則與具體的運(yùn)行程序有關(guān)。多數(shù)命令的選項(xiàng)不分前后順序。
有些工具的選項(xiàng)本身也要帶參數(shù)。如,gcc(GUN的c編譯器)的-o選項(xiàng)必須后跟gcc產(chǎn)生的可執(zhí)行文件名,通常選項(xiàng)與其參數(shù)間用空格隔開,如下:
[root@QUFENGBIN ~]# gcc -o prog prog.c
按照約定,工具的參數(shù)(如文件名)是允許以連字符開始的。這樣當(dāng)某個(gè)文件的名字為-l時(shí),命令的意義將不明確。如果創(chuàng)建了這類文件,那么,一些命令約定使用--(兩個(gè)連續(xù)的連字符)參數(shù)來表示選項(xiàng)的結(jié)束(和參數(shù)的開始)。如下示例:
[root@QUFENGBIN test]# touch -l touch: invalid option -- 'l' Try 'touch --help' for more information. [root@QUFENGBIN test]# touch -- -l [root@QUFENGBIN test]# ls -l total 4 -rw-r--r-- 1 root root 0 Apr 28 11:41 -l -rw-r--r-- 1 root root 14 Apr 26 16:26 test01 [root@QUFENGBIN test]# ls -- -l -l [root@QUFENGBIN test]# ls -l -- -l -rw-r--r-- 1 root root 0 Apr 28 11:41 -l
當(dāng)向命令行鍵入命令時(shí),Linux的tty設(shè)備驅(qū)動(dòng)程序(Linux操作系統(tǒng)內(nèi)核的一部分)將檢查每個(gè)字符,來確定是否要立即采取動(dòng)作。當(dāng)鍵入的字符不需要采取立即的動(dòng)作時(shí),設(shè)備驅(qū)動(dòng)程序?qū)炎址鎯?chǔ)在緩沖區(qū)中,等待字符輸入。當(dāng)按下回車鍵后,設(shè)備驅(qū)動(dòng)程序?qū)衙钚袀鬟f過程shell處理。
當(dāng)shell處理命令行時(shí),它將把命令行作為一個(gè)整體來對(duì)待,并將其分成幾個(gè)組成部分。接著,shell將查找命令的名稱。命令行中提示符后的第1項(xiàng)(即參數(shù)0)通常為命令名,因此shell將把命令行中從第1個(gè)字符到第一個(gè)空白字符(TAB或空格)之間的字符串作為命令名。命令名(第1個(gè)記號(hào))可采用簡(jiǎn)單文件名或路徑名的方式指定。例如:
[root@QUFENGBIN test]# ls -l test01 [root@QUFENGBIN test]# /bin/ls -l test01
當(dāng)在命令行上輸入絕對(duì)路徑名或非簡(jiǎn)單文件名的相對(duì)路徑名時(shí)(即輸入至少包含一條斜杠的路徑名),shell將在指定目錄下查找具有執(zhí)行權(quán)限的對(duì)應(yīng)文件。例如,輸入命令/bin/ls,shell將查找/bin目錄下具有執(zhí)行權(quán)限且名為ls的文件。當(dāng)輸入的是一個(gè)簡(jiǎn)單文件名時(shí),shell在一組目錄中查找與該文件名匹配且具有執(zhí)行權(quán)限的對(duì)應(yīng)文件。shell并不是在所有目錄下搜索,而只在PATH變量設(shè)定的路徑下搜索。
如果shell找到了與命令行上的命令具有相同名字的可執(zhí)行文件,那么,shell將啟動(dòng)一個(gè)新的進(jìn)程(進(jìn)程是指Linux命令的執(zhí)行),并將命令行上的命令名、參數(shù)、選項(xiàng)傳遞給程序(可執(zhí)行文件)。當(dāng)命令執(zhí)行時(shí),shell將等待進(jìn)程的結(jié)束,這時(shí)shell處于非活躍狀態(tài),稱為休眠狀態(tài)。當(dāng)程序執(zhí)行完畢,就將它的退出狀態(tài)傳遞給shell,這樣shell就返回到活躍狀態(tài)(被喚醒),顯示提示符,等待下一個(gè)命令的輸入。
由于shell不處理命令行上的參數(shù),只是將它們傳遞給調(diào)用的程序,所以shell不知道選項(xiàng)和參數(shù)是否對(duì)程序有效。所以關(guān)于選項(xiàng)和參數(shù)的錯(cuò)誤消息和用法消息都來自程序自身。也有些命令會(huì)忽略無效的選項(xiàng)。
標(biāo)準(zhǔn)輸出(standard output)是指程序輸出信息(如文本)的地方。程序從來都不“知道”它發(fā)送到標(biāo)準(zhǔn)輸出的信息究竟送往何處。這些信息可以輸出到打印機(jī)、普通文件或屏幕。默認(rèn)情況下,shell把命令的結(jié)果標(biāo)準(zhǔn)輸出到屏幕。shell也可以將輸出重定向到其他文件。
標(biāo)準(zhǔn)輸入(standard input)是程序信息的來源。而對(duì)于標(biāo)準(zhǔn)輸出,程序從不“知曉”信息的來源。默認(rèn)情況下,程序的輸入來自鍵盤輸入。
對(duì)一個(gè)運(yùn)行的程序來說,除了具有標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出外,通常還有錯(cuò)誤消息輸出,稱為標(biāo)準(zhǔn)錯(cuò)誤輸出(standard error)。
命令并不知道標(biāo)準(zhǔn)輸入來自哪,也不知道標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出到哪。
除了普通文件、目錄文件、硬鏈接和軟鏈接之外,Linux還有一種文件類型:設(shè)備文件(device file)。設(shè)備文件駐留在Linux文件結(jié)構(gòu)中(通常位于目錄/dev中),用來代表外圍設(shè)備,如終端模擬器、顯示屏、打印機(jī)和硬盤驅(qū)動(dòng)器。
在who工具顯示的內(nèi)容中,登錄名后的設(shè)備名即為屏幕的文件名。如果打開了多個(gè)窗口,每個(gè)打開的窗口都有對(duì)應(yīng)的設(shè)備名。在這些窗口中運(yùn)行tty工具即可得到它們各自的名稱??梢园堰@個(gè)設(shè)備文件看作是一個(gè)文本文件進(jìn)行讀寫。向該文件寫入會(huì)在屏幕上顯示寫入的內(nèi)容,而從該文件讀取就是從鍵盤上讀取鍵入的內(nèi)容。
[root@QUFENGBIN test]# tty /dev/pts/0 [root@QUFENGBIN test]# who root tty1 2018-04-17 15:44 root pts/0 2018-04-28 11:34 (111.113.5.18)
chsh:改變登錄shell
系統(tǒng)管理員在建立用戶賬戶時(shí),將確定用戶第一次登錄系統(tǒng)或打開GUI環(huán)境下終端模擬器窗口時(shí)使用的shell(見/etc/passwd文件)。
root:x:0:0:root:/root:/bin/bash .... ..... mysql:x:1000:1000::/home/mysql:/bin/false www:x:1001:1001::/home/www:/bin/false apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
但在登錄系統(tǒng)后,用戶可以自己決定運(yùn)行哪個(gè)shell。鍵入要使用的shell名(如bash,tcsh,或另一個(gè)shell),然后回車,則出現(xiàn)的提示符即為新設(shè)定shell給出的,輸入exit命令可退回到上一個(gè)shell。
使用工具chsh可以永久地修改登錄shell。首先輸入命令chsh,然后在提示符后輸入口令和要使用的shell的絕對(duì)路徑名(如/bin/bash或者/bin/tcsh,或者另一個(gè)shell的路徑名)。
當(dāng)?shù)谝淮蔚卿洉r(shí),shell將其標(biāo)準(zhǔn)輸出發(fā)送到代表屏幕的設(shè)備文件中,采用這種方式輸出可以把輸出內(nèi)容在屏幕上顯示出來。shell還將代表鍵盤的設(shè)備文件作為標(biāo)準(zhǔn)輸入的來源,這樣命令會(huì)把在鍵盤上鍵入的任何內(nèi)容作為輸入接收。
重定向(redirection)是指改變shell標(biāo)準(zhǔn)輸入來源和標(biāo)準(zhǔn)輸出去向的各種方式。例如,默認(rèn)情況下,shell將cat的標(biāo)準(zhǔn)輸入關(guān)聯(lián)到鍵盤,標(biāo)準(zhǔn)輸出關(guān)聯(lián)到屏幕。但也可以讓shell重定向任何命令的標(biāo)準(zhǔn)輸入或標(biāo)注輸出,方法就是將輸入或輸出與某命令或某文件關(guān)聯(lián),而不再是與代表鍵盤或屏幕的設(shè)備文件進(jìn)行關(guān)聯(lián)。
通過重定向符號(hào)(>)可以將shell命令的輸出重定向到指定的文件而不再是屏幕。重定向的命令格式為:
command [arguments] >filename
其中,command為可執(zhí)行程序(如應(yīng)用程序或者是工具),arguments是可選參數(shù),filename是shell要重定向輸出到的普通文件名。
重定向可能覆蓋文件!在重定向命令執(zhí)行前,如果該文件已經(jīng)存在,那么shell將重寫并覆蓋其原來的內(nèi)容。
與重定向標(biāo)準(zhǔn)輸出一樣,也可以重定向標(biāo)準(zhǔn)輸入。通過重定向標(biāo)準(zhǔn)輸入符號(hào)(<)可以使shell將命令的輸入重定向?yàn)閬碜灾付ǖ奈募辉偈擎I盤。重定向標(biāo)準(zhǔn)輸入的命令格式為:
command [arguments] <filename
其中,command為可執(zhí)行程序(如應(yīng)用程序或者是工具),arguments是可選參數(shù),filename是shell要重定向輸入來自的普通文件名。
將文件或者標(biāo)準(zhǔn)輸入作為輸入的工具:將命令cat的輸入重定向到文件的執(zhí)行結(jié)果與命令cat后跟文件名作為參數(shù)的執(zhí)行結(jié)果相同。像cat這樣具有這種特性的工具屬于Linux中的一類工具,這類工具還包括lpr、sort和grep。這類工具首先檢測(cè)調(diào)用它們的命令行。如果命令行上存在文件名,那么這類工具就把指定的文件作為輸入;否則,如果命令行上沒有指定文件名,那么這類工具就把標(biāo)準(zhǔn)輸入作為輸入。這種功能特性是該類工具自身所具有的,而與shell或者是操作系統(tǒng)無關(guān)。
shell提供了一種稱為noclobber的特性,該特性可防止重定向時(shí)不經(jīng)意地重寫了已存在的文件。
[root@QUFENGBIN test]# set -o noclobber [root@QUFENGBIN test]# echo "noclobber test" > test01 -bash: test01: cannot overwrite existing file [root@QUFENGBIN test]# set +o noclobber [root@QUFENGBIN test]# echo "noclobber test" > test01 [root@QUFENGBIN test]# cat test01 noclobber test
在重定向輸出符號(hào)后跟管道符號(hào),即使用符號(hào)組合“>|”可以忽略noclobber的設(shè)置。
[root@QUFENGBIN test]# set -o noclobber [root@QUFENGBIN test]# echo "noclobber test" > test01 -bash: test01: cannot overwrite existing file [root@QUFENGBIN test]# echo "noclobber test" >| test01 [root@QUFENGBIN test]# cat test01 noclobber test [root@QUFENGBIN test]# set +o noclobber
使用追加輸出符號(hào)(>>)可以向某個(gè)文件末尾添加新的內(nèi)容,并且不改變?cè)瓉硪延袃?nèi)容。
[root@QUFENGBIN test]# cat test01 noclobber test [root@QUFENGBIN test]# echo "noclobber test" > test01 ; cat test01 noclobber test [root@QUFENGBIN test]# echo "noclobber test" >> test01 ; cat test01 noclobber test noclobber test
設(shè)備/dev/null是一個(gè)數(shù)據(jù)接收器(data sink),通常被稱為位桶(bit bucket)。可以將不想看到或者是不想保存的數(shù)據(jù)重定向到/dev/null,這樣數(shù)據(jù)將不留痕跡的消失。
[root@QUFENGBIN test]# echo "noclobber test" > /dev/null
當(dāng)從/dev/null中讀取數(shù)據(jù)時(shí),將得到一個(gè)空字符串。
[root@QUFENGBIN test]# ls -l test01 -rw-r--r-- 1 root root 30 Apr 28 14:59 test01 [root@QUFENGBIN test]# cat /dev/null > test01 [root@QUFENGBIN test]# ls -l test01 -rw-r--r-- 1 root root 0 Apr 28 15:05 test01
shell使用管道將一個(gè)命令的輸出直接連接到另一個(gè)命令的輸入。管道(pipe,有時(shí)被稱為pipeline)的功能實(shí)現(xiàn)類似于下面的過程:首先將一個(gè)命令的標(biāo)準(zhǔn)輸出重定向到一個(gè)文件,然后將該文件作為另一個(gè)命令的標(biāo)準(zhǔn)輸入。管道不會(huì)單獨(dú)處理每條命令,并且不需要中間文件。管道的符號(hào)為一條豎線(|),命令行語(yǔ)法格式為:
command_a [arguments] | command_b [arguments]
上面的命令行得到的結(jié)果與下面的這一組命令得到的結(jié)果相同:
command_a [arguments] > temp command_b [arguments] < temp rm remp
任何Linux工具都可以使用管道從命令行上指定的文件中接受輸入,也可以從標(biāo)準(zhǔn)輸入接受輸入。
有些使用管道的命令僅從標(biāo)準(zhǔn)輸入接受輸入,如工具tr(transtate,轉(zhuǎn)換)就只能從標(biāo)準(zhǔn)輸入接受輸入(即tr只能通過標(biāo)準(zhǔn)輸入接受輸入,而無法通過命令行參數(shù)來接受輸入)。
使用tr的最簡(jiǎn)單格式:tr string1 string2
tr工具從標(biāo)準(zhǔn)輸入接受輸入,查找與string1匹配的字符,找到一個(gè)匹配就將string1的字符替換為string2中對(duì)應(yīng)字符。tr工具將它的輸出發(fā)送到標(biāo)準(zhǔn)輸出。
[root@QUFENGBIN test]# tr abc ABC < test01 ABCdefgABCDEFG [root@QUFENGBIN test]# cat test01 | tr abc ABC ABCdefgABCDEFG [root@QUFENGBIN test]# tr abc ABC test01 tr: extra operand ‘test01’ Try 'tr --help' for more information.
1.過濾器
過濾器(filter)是將輸入數(shù)據(jù)流處理后在輸出數(shù)據(jù)流的一類命令。包含過濾器的命令行用一個(gè)管道將某個(gè)命令的標(biāo)準(zhǔn)輸出連接到過濾器的標(biāo)準(zhǔn)輸入,用另一個(gè)管道將過濾器的標(biāo)準(zhǔn)輸出連接到另一個(gè)命令的標(biāo)準(zhǔn)輸入。并不是所有的工具都可以用作過濾器。
2.tee:向兩個(gè)方向輸入
tee工具將標(biāo)準(zhǔn)輸入復(fù)制到文件和標(biāo)準(zhǔn)輸出。該工具被命名為tee是因?yàn)椋核挥幸粋€(gè)輸入,但輸出到兩個(gè)方向。
[root@QUFENGBIN test]# who | tee who.out | grep root root tty1 2018-04-17 15:44 root pts/0 2018-04-28 14:50 (111.113.5.18) [root@QUFENGBIN test]# cat who.out root tty1 2018-04-17 15:44 root pts/0 2018-04-28 14:50 (111.113.5.18)
前臺(tái):當(dāng)在前臺(tái)運(yùn)行命令時(shí),shell將一直等到命令執(zhí)行完畢。才會(huì)給出提示符使得你可繼續(xù)輸入下一個(gè)命令。當(dāng)命令在后臺(tái)運(yùn)行時(shí),就不必等待該命令完成,可直接輸入另一個(gè)命令。
作業(yè):作業(yè)(job)是由一個(gè)或者(可通過管道連接的)多個(gè)命令組成的序列。前臺(tái)只能有一個(gè)作業(yè)位于窗口或屏幕中,但可以有多個(gè)作業(yè)在后臺(tái)運(yùn)行。同一時(shí)間運(yùn)行多個(gè)作業(yè)是Linux的重要特性,這常被稱為多任務(wù)特性。
作業(yè)編號(hào)與PID號(hào):如果在命令行的末尾輸入與符號(hào)(&)后回車,那么shell將在后臺(tái)運(yùn)行這個(gè)作業(yè)。同時(shí),shell會(huì)給這個(gè)作業(yè)分配一個(gè)作業(yè)編號(hào)(是個(gè)小數(shù)字),并將其顯示在方括號(hào)內(nèi)。在作業(yè)編號(hào)之后,shell將顯示進(jìn)程標(biāo)識(shí)(process identification,PID)號(hào),該號(hào)是由操作系統(tǒng)分配的一個(gè)大數(shù)。每個(gè)大數(shù)后面都標(biāo)識(shí)了后臺(tái)運(yùn)行的一條命令。然后,shell將顯示另一個(gè)提示符,這是便可以鍵入另一個(gè)命令。當(dāng)后臺(tái)作業(yè)運(yùn)行結(jié)束時(shí),shell將顯示一個(gè)消息,這個(gè)消息的內(nèi)容為:已結(jié)束作業(yè)的作業(yè)編號(hào)和運(yùn)行該作業(yè)的命令行。
CONTROL+Z:程序掛起鍵,shell把前臺(tái)的作業(yè)掛起(阻止其繼續(xù)運(yùn)行),并終止作業(yè)中的進(jìn)程,將進(jìn)程的標(biāo)準(zhǔn)輸入與鍵盤隔開。用bg命令后跟作業(yè)編號(hào)可以把掛起的作業(yè)放到后臺(tái)執(zhí)行。如果僅有一個(gè)作業(yè)被掛起。那么可以不必指明作業(yè)編號(hào)。只有前臺(tái)作業(yè)可以從鍵盤獲得輸入。為了將鍵盤和后臺(tái)某個(gè)正運(yùn)行的作業(yè)連接起來,必須把該后臺(tái)作業(yè)移至前臺(tái)。用fg命令后跟作業(yè)編號(hào)可以把后臺(tái)的作業(yè)移至前臺(tái)。不帶任何參數(shù)的fg命令可以將后臺(tái)唯一的作業(yè)移至前臺(tái)。
命令行上輸入kill后跟進(jìn)程的PID號(hào)(或者后跟%和作業(yè)編號(hào)),可以將后臺(tái)正在運(yùn)行的進(jìn)程(或作業(yè))終止,使用中斷鍵(通常CONTROL+C)是不能實(shí)現(xiàn)其功能的。
通配符和通配:當(dāng)輸入包含特殊字符(也稱為元字符)的部分文件名時(shí),shell可以生成與已有文件的名字匹配的文件名。這些特殊的字符也常常被稱為通配符(wildcard)。當(dāng)某個(gè)特殊字符作為參數(shù)出現(xiàn)在命令行上時(shí),shell將該參數(shù)擴(kuò)展為有序的文件名列表,并將列表傳遞給命令行上調(diào)用的程序。包含特殊字符的文件名稱為模糊文件引用(ambiguous file reference),因?yàn)樗鼈儾慌c任何一個(gè)特定文件相關(guān)聯(lián)。對(duì)這些文件名操作的過程稱為路徑名展開(path expansion)或者通配(globbing)。
問號(hào)(?)是shell生成文件名的特殊字符,它與已有文件名中的某個(gè)單獨(dú)字符匹配。
[root@QUFENGBIN test]# ls test0? test01 [root@QUFENGBIN test]# echo wh?.out who.out [root@QUFENGBIN test]# cat wh?.out root tty1 2018-04-17 15:44 root pts/0 2018-04-28 14:50 (111.113.5.18)
星號(hào)(*)的功能與問號(hào)的類似,不同之處在于,星號(hào)可以跟文件名中的任意多個(gè)(包括0個(gè))字符匹配。
用方括號(hào)將一個(gè)字符列表括起來使得shell與包含列表中每個(gè)單獨(dú)字符的文件名進(jìn)行匹配。例如,test?可匹配test后跟任何一個(gè)字符的文件名,而方括號(hào)更嚴(yán)格些,test[01]僅與test0、test1匹配。這里,方括號(hào)定義了一個(gè)字符類(character class),該類由括號(hào)內(nèi)的所有字符組成。
每個(gè)定義字符類只能替換文件名中的一個(gè)字符。方括號(hào)和其中的內(nèi)容合起來的功能就如同問號(hào)一樣,但是只能用字符類中的一個(gè)成員替換。
ps:左方括號(hào)后直接跟嘆號(hào)(!)或脫字符(^)也可以定義字符類,該類與任何不在方括號(hào)內(nèi)的字符匹配。例如,[^ab]*與不以a或b開始的文件名匹配。
[root@QUFENGBIN test]# ls aa ab ac ad ba bb bc bd cc dd [root@QUFENGBIN test]# ls *[^ab] ac ad bc bd cc dd [root@QUFENGBIN test]# ls [b-d]* ba bb bc bd cc dd
下面的例子表示ls工具不能翻譯模糊文件引用。第一個(gè)ls命令帶有參數(shù)aa*,shell將其擴(kuò)展為匹配的文件名aa,并將該名字傳遞給ls。第二個(gè)命令將*轉(zhuǎn)義,shell不再將*看作特殊字符,并將其傳遞給ls,ls報(bào)錯(cuò)。大多數(shù)工具和程序像ls一樣也不能解釋模糊文件引用,該解釋工作由shell完成。
[root@QUFENGBIN test]# ls aa* aa [root@QUFENGBIN test]# ls aa\* ls: cannot access aa*: No such file or directory [root@QUFENGBIN test]# ls aaa* ls: cannot access aaa*: No such file or directory
注意:模糊文件引用由shell進(jìn)行擴(kuò)展,而不是shell調(diào)用的程序進(jìn)行擴(kuò)展。上面的例子都不能“看到”模糊文件引用。shell對(duì)模糊文件引用進(jìn)行擴(kuò)展,并將擴(kuò)展得到的文件列表傳遞給工具。在下面的echo例子中驗(yàn)證了這一點(diǎn),因?yàn)樗@示了參數(shù)而不是模糊文件引用。
[root@QUFENGBIN test]# ls aa ab ac ad ba bb bc bd cc dd [root@QUFENGBIN test]# echo a? aa ab ac ad [root@QUFENGBIN test]# echo * aa ab ac ad ba bb bc bd cc dd [root@QUFENGBIN test]# echo a* aa ab ac ad [root@QUFENGBIN test]# echo .* . .. [root@QUFENGBIN test]# echo [a-m]* aa ab ac ad ba bb bc bd cc dd [root@QUFENGBIN test]# echo [x-z]* [x-z]* [root@QUFENGBIN test]# echo *[a-d] aa ab ac ad ba bb bc bd cc dd [root@QUFENGBIN test]# echo *[x-z] *[x-z] [root@QUFENGBIN test]# echo [a-d]\* [a-d]* [root@QUFENGBIN test]# echo [x-z]\* [x-z]*
外部命令
外部命令,有時(shí)候也被稱為文件系統(tǒng)命令,是存在于bash shell之外的程序。它們并不是shell程序的一部分。外部命令程序通常位于/bin、/usr/bin、/sbin或/usr/sbin中。ps是一個(gè)外部命令,你可以使用which和type命令找到它。
當(dāng)外部命令執(zhí)行時(shí),會(huì)創(chuàng)建出一個(gè)子進(jìn)程。這種操作被稱為衍生(forking)。
內(nèi)置命令(內(nèi)建命令)
內(nèi)建命令和外部命令的區(qū)別在于前者不需要使用子進(jìn)程來執(zhí)行。它們已經(jīng)和shell編譯成了一體,作為shell工具的組成部分存在。不需要借助外部程序文件來運(yùn)行??梢岳?type 命令來了解某個(gè)命令是否是內(nèi)建的。每個(gè)shell都有自己的內(nèi)置命令集合。
輸入命令“man bash”,再輸入命令“/^SHELL BUILTIN COMMANDS”,shell將在內(nèi)置命令部分搜索始于SHELL的行,從而可以查看內(nèi)置命令的man頁(yè)內(nèi)容。
要點(diǎn):初始化文件、重定向標(biāo)準(zhǔn)錯(cuò)誤輸出、編寫簡(jiǎn)單的shell腳本、作業(yè)控制、操作目錄棧、參數(shù)和變量、進(jìn)程、命令歷史機(jī)制、重新執(zhí)行和編輯命令、別名、函數(shù)、控制bash特性和選項(xiàng)、處理命令行
Bourne Again Shell是一種命令解釋器,同時(shí)也是一種高級(jí)編程語(yǔ)言。作為命令解釋器,它們通過提示符響應(yīng)并處理用戶在命令行界面上輸入的命令。而作為一種編程語(yǔ)言,它們將處理存放在所謂shell腳本文件中的命令。
內(nèi)容包括編寫和使用初始化文件、重定向標(biāo)準(zhǔn)錯(cuò)誤輸出、編寫和執(zhí)行簡(jiǎn)單的shell腳本、命令分割和分組、實(shí)現(xiàn)作業(yè)控制和操作目錄棧。
當(dāng)啟動(dòng)shell時(shí),它將運(yùn)行初始化文件初始化自己。具體運(yùn)行哪個(gè)文件取決于該shell是一個(gè)登錄shell還是一個(gè)非登錄shell的交互式shell(比如通過命令bash),又或者是一個(gè)非交互式shell(用來執(zhí)行shell腳本)。要想運(yùn)行初始化文件中的命令,用戶必須具備讀權(quán)限。
登錄shell本來就屬于交互式shell。
/etc/profile:shell首先執(zhí)行/etc/profile中的命令。通過設(shè)置這個(gè)文件,超級(jí)用戶可以為全系統(tǒng)內(nèi)的所有bash用戶建立默認(rèn)特征。
.bash_profile、.bash_login和.profile:然后shell依次查找~/.bash_profile、~/.bash_login和~/.profile,并執(zhí)行它找到的首個(gè)文件中的命令??梢詫⒚罘胖迷谶@些文件中的某個(gè)里以覆蓋掉/etc/profile文件中的默認(rèn)設(shè)置。
.bash_logout:當(dāng)用戶注銷時(shí),bash執(zhí)行文件~/.bash_logout中的命令。這個(gè)文件包含了退出會(huì)話時(shí)需要執(zhí)行的清理任務(wù)(比如刪除臨時(shí)文件)常用到的命令。
在交互式非登錄shell中并不執(zhí)行前面提到的初始化文件中的命令。然而,交互式非登錄shell從登錄shell繼承了由這些初始化文件設(shè)置的shell變量。
/etc/bashrc:盡管不是通過bash直接調(diào)用,許多~/.bashrc文件還是調(diào)用/etc/bashrc。這種安排使得超級(jí)用戶可以為全系統(tǒng)內(nèi)的非登錄bash shell建立默認(rèn)特性。
.bashrc:交互式非登錄shell執(zhí)行~/.bashrc文件中的命令,而登錄shell的初始化文件(比如.bash_profile)通常會(huì)運(yùn)行這個(gè)文件。這樣,登錄shell和非登錄shell都可以使用.bashrc中的命令。
非交互式shell(如那些運(yùn)行shell腳本的shell)并不執(zhí)行前面描述的初始化文件中的命令。然而,這些shell從登錄shell那里繼承了由這些初始化文件設(shè)置的shell變量。
BASH_ENV:非交互式shell查找環(huán)境變量BASH_ENV(或者當(dāng)shell作為sh調(diào)用時(shí)為ENV),并執(zhí)行由該變量命名的文件中的命令。
盡管有很多種初始化文件和shell,但是用戶通常只需要主目錄下的.bash_profile和.bashrc文件。.bash_profile中通過以下命令將為登錄shell執(zhí)行.bashrc(如果該文件存在)中的命令。
if [ -f ~/.bashrc ]; then . ~/.bashrc fi
在編輯諸如.bashrc這類的初始化文件之后,要使這些修改起作用,用戶沒有必要注銷然后再次登錄,可以使用內(nèi)置命令“.”(句點(diǎn))或者source(這是兩個(gè)相同的命令)。與其他命令一樣,在命令行上,“.”后面必須有一個(gè)空格。內(nèi)置命令“.”或者source用起來類似于運(yùn)行一個(gè)shell腳本,但是這些命令將該腳本作為當(dāng)前進(jìn)程的一部分運(yùn)行。因此,當(dāng)使用“.”或者source運(yùn)行腳本的時(shí)候,在腳本中改變的變量也將影響到運(yùn)行該腳本的shell??梢允褂谩?”或者source命令來運(yùn)行任何shell腳本,而不僅僅是初始化文件,但是可能會(huì)帶來副作用(比如可能修改用戶依賴的shell變量的值)。如果將初始化文件作為常規(guī)shell腳本運(yùn)行,并且不使用“.”或source內(nèi)置命令,那么啟動(dòng)腳本中創(chuàng)建的變量將只在運(yùn)行該腳本的子shell中起作用。
Bourne Again Shell以多種方式使用符號(hào)(、)、[、]和$。為了避免混淆,下表列出了每種符號(hào)最通用的用法。 | 符號(hào) | 命令 |
---|---|---|
() | 子shell | |
$() | 命令替換 | |
(()) | 算術(shù)表達(dá)式計(jì)算,let的同義詞(當(dāng)被括起來的值中包含等號(hào)時(shí)使用) | |
$(()) | 算術(shù)展開(不用于被括起來的值中包含等號(hào)的情形) | |
[] | test命令 | |
[[]] | 條件表達(dá)式,類似于[],但是添加了字符串比較 |
除了標(biāo)準(zhǔn)輸出之外,命令還可以將輸出發(fā)送到標(biāo)準(zhǔn)錯(cuò)誤輸出(standard error)。命令將錯(cuò)誤消息發(fā)送到標(biāo)準(zhǔn)錯(cuò)誤輸出,這樣就可以避免與發(fā)送到標(biāo)準(zhǔn)輸出的信息混淆在一起。
與處理標(biāo)準(zhǔn)輸出一樣,默認(rèn)情況下,shell 將命令的標(biāo)準(zhǔn)錯(cuò)誤輸出發(fā)送到屏幕上。除非將標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出中的某一個(gè)重定向,否則不能區(qū)分命令的輸出到底是標(biāo)準(zhǔn)輸出還是標(biāo)準(zhǔn)錯(cuò)誤輸出。
文件描述符:文件描述符(file descriptor)是程序發(fā)送輸出和獲取輸入的地方。當(dāng)執(zhí)行一個(gè)程序時(shí),運(yùn)行該程序的進(jìn)程打開了 3 個(gè)文件描述符,分別是:0(標(biāo)準(zhǔn)輸入)、1(標(biāo)準(zhǔn)輸出)和 2(標(biāo)準(zhǔn)錯(cuò)誤輸出)。重定向標(biāo)準(zhǔn)輸出符號(hào)(>)是 1> 的簡(jiǎn)寫,它通知 shell 將標(biāo)準(zhǔn)輸出重定向。類似地,< 是 0< 的簡(jiǎn)寫,表示將標(biāo)準(zhǔn)輸入重定向。符號(hào) 2> 將標(biāo)準(zhǔn)錯(cuò)誤輸出重定向。
下面是個(gè)例子:
當(dāng)運(yùn)行 cat 時(shí),如果所帶參數(shù)中的某個(gè)文件不存在,而另一個(gè)文件存在,那么 cat 將發(fā)送一條錯(cuò)誤消息到標(biāo)準(zhǔn)錯(cuò)誤輸出,同時(shí)還將已存在的那個(gè)文件復(fù)制一份到標(biāo)準(zhǔn)輸出。除非將它們重定向,否則兩條消息都將出現(xiàn)在屏幕上。
[root@QUFENGBIN test]# cat y This is y [root@QUFENGBIN test]# cat x cat: x: No such file or directory [root@QUFENGBIN test]# cat x y cat: x: No such file or directory This is y
將命令的標(biāo)準(zhǔn)輸出重定向時(shí),發(fā)送到標(biāo)準(zhǔn)錯(cuò)誤輸出的輸出結(jié)果將不受影響,仍然出現(xiàn)在屏幕上。
[root@QUFENGBIN test]# cat x y > hold cat: x: No such file or directory [root@QUFENGBIN test]# cat hold This is y [root@QUFENGBIN test]# cat x y 1> hold1 2>hold2 [root@QUFENGBIN test]# cat hold1 This is y [root@QUFENGBIN test]# cat hold2 cat: x: No such file or directory
復(fù)制文件描述符:在下一個(gè)例子中,1> 將標(biāo)準(zhǔn)輸出重定向到文件hold。然后,2>&1 聲明文件描述符 2 為文件描述符 1 的副本。結(jié)果是, 標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出均被重定向到文件hold中。
root@QUFENGBIN test]# cat x y 1>hold 2>&1 [root@QUFENGBIN test]# cat hold cat: x: No such file or directory This is y
在上面這個(gè)示例中,1>hold 放在了 2>&1 的前面。如果將它們的順序顛倒的話,在標(biāo)準(zhǔn)輸出重定向到文件 hold 之前,標(biāo)準(zhǔn)錯(cuò)誤輸出就已經(jīng)拷貝了標(biāo)準(zhǔn)輸出的一個(gè)副本。這樣一來,就只有標(biāo)準(zhǔn)輸出被重定向到文件hold。
[root@QUFENGBIN test]# cat x y 2>&1 1>hold cat: x: No such file or directory [root@QUFENGBIN test]# cat hold This is y [root@QUFENGBIN test]# cat x y 2>&1 cat: x: No such file or directory This is y
Bourne Again Shell所支持的重定向操作符如下表。
操作符 | 含義 |
---|---|
<filename | 將標(biāo)準(zhǔn)輸入重定向?yàn)槲募?filename |
>filename | 除非文件 filename 已存在并且設(shè)置了 noclobber 標(biāo)記,否則標(biāo)準(zhǔn)輸出將被重定向到文件 filename 。如果文件 filename 不存在且沒有設(shè)置 noclobber 標(biāo)記,那么重定向操作將創(chuàng)建該文件 |
>|filename | 即使文件 filename 已存在并且設(shè)置了 noclobber 標(biāo)記,仍將標(biāo)準(zhǔn)輸出重定向到該文件 |
>>filename | 除非文件 filename 已存在并且設(shè)置了 noclobber 標(biāo)記,否則標(biāo)準(zhǔn)輸出將被重定向到文件 filename,并將內(nèi)容添加到原文件的末尾。如果文件 filename 不存在且沒有設(shè)置 noclobber 標(biāo)記,那么將創(chuàng)建該文件 |
<&m | 從文件描述符m復(fù)制標(biāo)準(zhǔn)輸入 |
[n]>&m | 從文件描述符m復(fù)制標(biāo)準(zhǔn)輸出或者文件描述符n(如果命令中指定了n) |
[n]<&- | 關(guān)閉標(biāo)準(zhǔn)輸入或者文件描述符n(如果指定了n) |
[n]>&- | 關(guān)閉標(biāo)準(zhǔn)輸出或者文件描述符n(如果指定了n) |
shell 腳本是包含 shell 可執(zhí)行命令的文件。shell 腳本中的命令可以是用戶在 shell 提示符后面輸入的任何命令。除了可以使用用戶在命令行下面輸入的命令之外,shell 腳本還可以使用控制流(control flow)命令(亦稱為控制結(jié)構(gòu)(control structure))。使用這組命令可以改變腳本中命令的執(zhí)行順序。
任何用戶想把文件名作為命令行執(zhí)行,都必須具備執(zhí)行訪問權(quán)。如果該文件是一個(gè) shel l腳本,用戶嘗試執(zhí)行這個(gè)文件時(shí),還必須具備讀訪問權(quán)限。而在執(zhí)行一個(gè)二進(jìn)制可執(zhí)行文件(已編譯程序)時(shí),并不需要讀訪問權(quán)限。
[root@QUFENGBIN test]# ll whoson -rw-r--r-- 1 root root 41 Apr 30 20:09 whoson [root@QUFENGBIN test]# cat whoson date echo "User Currently Logged In" who [root@QUFENGBIN test]# whoson -bash: whoson: command not found [root@QUFENGBIN test]# ./whoson -bash: ./whoson: Permission denied [root@QUFENGBIN test]# chmod u+x whoson [root@QUFENGBIN test]# ./whoson Mon Apr 30 21:36:18 CST 2018 User Currently Logged In root tty1 2018-04-17 15:44 root pts/0 2018-04-30 11:55 (118.74.57.231) [root@QUFENGBIN test]# whoson -bash: whoson: command not found [root@QUFENGBIN test]# PATH=$PATH:. [root@QUFENGBIN test]# whoson Mon Apr 30 21:36:53 CST 2018 User Currently Logged In root tty1 2018-04-17 15:44 root pts/0 2018-04-30 11:55 (118.74.57.231)
在 shell 腳本文件的第一行可以放置一行特殊的字符串,告訴操作系統(tǒng)使用哪個(gè) shell 來執(zhí)行這個(gè)文件。因?yàn)椴僮飨到y(tǒng)在試圖 exec 文件之前檢查該程序的開頭字符串,這些字符讓操作系統(tǒng)不必進(jìn)行失敗的嘗試。如果腳本的前兩個(gè)字符是 #! ,那么系統(tǒng)將這兩個(gè)字符后面的那些字符作為用來執(zhí)行該腳本的命令解釋器的絕對(duì)路徑名。它可以是任何程序的路徑名,而不僅僅是 shell 。
fork 和 exec 系統(tǒng)調(diào)用:用戶在命令行上輸入一條命令之后,shell 將 fork 一個(gè)新的進(jìn)程,以創(chuàng)建當(dāng)前 shell 進(jìn)程的一個(gè)副本(子shell)。這個(gè)新的進(jìn)程將試圖 exec(execute,執(zhí)行)該命令。與 fork 一樣,exec 例程也是由操作系統(tǒng)執(zhí)行(系統(tǒng)調(diào)用)。如果該命令是一個(gè)二進(jìn)制可執(zhí)行程序,比如編譯好的 C 程序,那么 exec 執(zhí)行成功,系統(tǒng)調(diào)用該可執(zhí)行程序?qū)⑿聞?chuàng)建的子 shell 覆蓋掉。而如果這個(gè)命令是一個(gè) shell 腳本,exec 執(zhí)行失敗。當(dāng) exec 失敗時(shí),將會(huì)假設(shè)該命令是一個(gè) shell 腳本,子 shell 將執(zhí)行腳本中的命令。與登錄 shell 期望從命令行讀取輸入不同,子 shell 從文件(shell 腳本)中獲取輸入。所以,如果不具備 shell 腳本文件的執(zhí)行權(quán)限,那么,用戶可以使用 bash 命令來 exec 一個(gè) shell 直接運(yùn)行該腳本,這樣就可以運(yùn)行腳本中的命令。
fork ( ~/test/test01.sh) :如果 shell 中包含執(zhí)行命令,那么子命令并不影響父級(jí)的命令,在子命令執(zhí)行完后再執(zhí)行父級(jí)命令。子級(jí)的環(huán)境變量不會(huì)影響到父級(jí)。
說明:fork 是最普通的, 就是直接在腳本里面用 ~/test/test01.sh 來調(diào)用 test01.sh 這個(gè)腳本。運(yùn)行的時(shí)候開一個(gè) sub-shell 執(zhí)行調(diào)用的腳本,sub-shell 執(zhí)行的時(shí)候, parent-shell 還在。sub-shell 執(zhí)行完畢后返回 parent-shell.。sub-shell 從 parent-shell 繼承環(huán)境變量,但是 sub-shell 中的環(huán)境變量不會(huì)帶回 parent-shell。
exec (exec ~/test/test01.sh):執(zhí)行子級(jí)的命令后,不再執(zhí)行父級(jí)命令。
說明:exec 與 fork不同,不需要新開一個(gè) sub-shell 來執(zhí)行被調(diào)用的腳本。被調(diào)用的腳本與父腳本在同一個(gè) shell 內(nèi)執(zhí)行。但是使用 exec 調(diào)用一個(gè)新腳本以后, 父腳本中 exec 行之后的內(nèi)容就不會(huì)再執(zhí)行了。這是 exec 和source 的區(qū)別。
source (source ~/test/test01.sh):執(zhí)行子級(jí)命令后繼續(xù)執(zhí)行父級(jí)命令,同時(shí)子級(jí)設(shè)置的環(huán)境變量會(huì)影響到父級(jí)的環(huán)境變量。
說明:與 fork 的區(qū)別是不新開一個(gè) sub-shell 來執(zhí)行被調(diào)用的腳本,而是在同一個(gè) shell 中執(zhí)行。 所以被調(diào)用的腳本中聲明的變量和環(huán)境變量,都可以在主腳本中得到和使用。
[root@QUFENGBIN test]# chmod u+x test01.sh [root@QUFENGBIN test]# chmod u+x test02.sh [root@QUFENGBIN test]# cat test01.sh #!/bin/bash A=B echo "PID for test01.sh before exec/source/fork:$$" export A echo "test01.sh: \$A is $A" case $1 in exec) echo "using exec…" exec ./test02.sh ;; source) echo "using source…" . ./test02.sh ;; *) echo "using fork by default…" ./test02.sh ;; esac echo "PID for test01.sh after exec/source/fork:$$" echo "test01.sh: \$A is $A" [root@QUFENGBIN test]# cat test02.sh #!/bin/bash echo "PID for test02.sh: $$" echo "test02.sh get \$A=$A from test01.sh" A=C export A echo "test02.sh: \$A is $A" [root@QUFENGBIN test]# ./test01.sh PID for test01.sh before exec/source/fork:1259 test01.sh: $A is B using fork by default… PID for test02.sh: 1260 test02.sh get $A=B from test01.sh test02.sh: $A is C PID for test01.sh after exec/source/fork:1259 test01.sh: $A is B [root@QUFENGBIN test]# ./test01.sh exec PID for test01.sh before exec/source/fork:1261 test01.sh: $A is B using exec… PID for test02.sh: 1261 test02.sh get $A=B from test01.sh test02.sh: $A is C [root@QUFENGBIN test]# ./test01.sh source PID for test01.sh before exec/source/fork:1262 test01.sh: $A is B using source… PID for test02.sh: 1262 test02.sh get $A=B from test01.sh test02.sh: $A is C PID for test01.sh after exec/source/fork:1262 test01.sh: $A is C
什么是環(huán)境變量
bash shell 通過一個(gè)叫做環(huán)境變量(environment variable)的特性來存儲(chǔ)有關(guān) shell 會(huì)話和工作環(huán)境的信息(這也是它們被稱為環(huán)境變量的信息)。這項(xiàng)特性允許你在內(nèi)存中存儲(chǔ)數(shù)據(jù),一遍程序或 shell 在運(yùn)行的腳本能夠輕松的訪問它們。在 bash shell 中,環(huán)境變量分為兩類:全局變量、局部變量。
全局環(huán)境變量
全局環(huán)境變量對(duì)于 shell 會(huì)話和所有生成的子 shell 都是可見的。局部變量則只對(duì)于創(chuàng)建它們的 shell 可見。Linux 系統(tǒng)在開始 bash 會(huì)話前就設(shè)置了一些全局環(huán)境變量。系統(tǒng)環(huán)境變量基本上都使用全大寫字母,以區(qū)別于普通用戶的環(huán)境變量。要查看全局環(huán)境變量,可使用 env 命令或者 printenv 命令。
變量
在 shell 中,shell 參數(shù)(shell parameter)與用戶可訪問的某個(gè)值相關(guān),有幾種不同的 shell 參數(shù)。參數(shù)的名字由字母、數(shù)字和下劃線組成,常被稱為 shell 變量(shell variable),或者簡(jiǎn)稱為變量(variable)。變量名必須以字母或者下劃線開頭,而不能是數(shù)字。
用戶創(chuàng)建的變量
用戶命令或賦值的 shell 變量稱為用戶創(chuàng)建的變量(user-created variable)。用戶可以在任何時(shí)候修改用戶創(chuàng)建的變量的值,或者將其設(shè)置為只讀。還可以將用戶創(chuàng)建的變量變成全局的。全局變量(又稱為環(huán)境變量)可以被任何shell和從最初shell創(chuàng)建的其它程序訪問。這里有一個(gè)命名約定,即全局變量只使用大寫字母,而其它變量則使用大小寫混合命名。
關(guān)鍵字變量
關(guān)鍵字 shell 變量(keyword shell variable,簡(jiǎn)稱為關(guān)鍵字變量)對(duì)于 shell 而言,具有特殊的意義,它們的名字一般比較短而且有助于記憶。當(dāng)用戶啟動(dòng) shell 的時(shí)候(比如登錄),shell 將從環(huán)境中繼承幾個(gè)關(guān)鍵字變量。HOME 和 PATH 就屬于這樣的變量。
位置參數(shù)和特殊參數(shù)
位置參數(shù)和特殊參數(shù)的名字并不像變量名。其中,大多數(shù)參數(shù)的名字都只由一個(gè)字符組成(比如1、?和#等),并且像其他所有變量一樣,在引用它們時(shí)一般在其名字前面加上美元符號(hào)(如$1、$?和$#)。這些參數(shù)的值反映了用戶與 shell 交互的不同方面。無論何時(shí),用戶輸入的一行命令中的每個(gè)參數(shù)都將成為位置參數(shù)(positional parameter)的值。用戶使用位置參數(shù)可以訪問命令行參數(shù),在編寫 shell 腳本時(shí)將用到這項(xiàng)功能。內(nèi)置命令 set 可以用來對(duì)位置參數(shù)賦值。其他經(jīng)常需要用到的 shell 腳本值,比如最后一次執(zhí)行的命令名、命令行參數(shù)的個(gè)數(shù)以及最近執(zhí)行命令的狀態(tài),這些值均保存在特殊參數(shù)(special parameter)中。用戶不能對(duì)特殊參數(shù)賦值。
[root@aminglinux_01 ~]# person=alex [root@aminglinux_01 ~]# echo person person [root@aminglinux_01 ~]# echo $person alex
命令echo $person顯示變量person的值,而不是顯示$person,這是因?yàn)椴粫?huì)將$person作為參數(shù)傳遞給echo。由于名字開頭出現(xiàn)$,因而shell識(shí)別出這是一個(gè)變量的名字,并將變量的值代入,同時(shí)將該值傳遞給echo。內(nèi)置命令echo顯示該變量的值,而不是它的名字,然而echo絕不會(huì)知道用戶調(diào)用它時(shí)使用了變量
引用$:如果將開頭的$用單引號(hào)引起來,就可以阻止shell代入變量的值。雙引號(hào)不能阻止代入(會(huì)把引號(hào)之間的所有字符代入,包括單引號(hào)),而單引號(hào)和反斜杠符號(hào)\都可以阻止代入。
[root@aminglinux_01 ~]# echo $person alex [root@aminglinux_01 ~]# echo "$person" alex [root@aminglinux_01 ~]# echo '$person' $person [root@aminglinux_01 ~]# echo \$person $person [root@aminglinux_01 ~]# echo "'$person'" 'alex' [root@aminglinux_01 ~]# echo "'\$person'" '$person'
空格符:雙引號(hào)不能阻止變量替換,但是可以關(guān)閉大多數(shù)其他字符的特殊含義。
[root@aminglinux_01 ~]# person="alex and jenny" [root@aminglinux_01 ~]# echo $person alex and jenny [root@aminglinux_01 ~]# person=alex and jenny -bash: and: 未找到命令
當(dāng)引用一個(gè)包含制表符和多個(gè)相連空格符的變量時(shí),需要使用引號(hào)來保留這些空格。如果沒有將該變量用引號(hào)引起來,在將其傳遞給工具之前,shell將把每個(gè)空白字符構(gòu)成的串壓縮成單個(gè)空格符:
[root@aminglinux_01 ~]# person="alex and jenny" [root@aminglinux_01 ~]# echo $person alex and jenny [root@aminglinux_01 ~]# echo "$person" alex and jenny
賦值中的路徑名展開:當(dāng)引用一個(gè)包含未被引號(hào)引起來的特殊字符的變量時(shí),所有 shell 均將這些字符解釋為特殊字符。
[root@aminglinux_01 test]# ls 1.txt 2.txt alex.1 alex.2 [root@aminglinux_01 test]# memo=alex* [root@aminglinux_01 test]# echo $memo alex.1 alex.2 [root@aminglinux_01 test]# echo "$memo" alex*
PS:語(yǔ)法 $VARIABLE 是 ${VARIABLE} 的特殊情形,后者要更加通用,它將變量名用${}括起來?;ɡㄌ?hào)將變量名隔離起來。將一個(gè)變量和一個(gè)字符串連接起來的時(shí)候,花括號(hào)是必要的:
[root@aminglinux_01 test]# PREF=counter [root@aminglinux_01 test]# WAY=$PREFclock [root@aminglinux_01 test]# FAKE=$PREFfeit [root@aminglinux_01 test]# echo $WAY $FAKE [root@aminglinux_01 test]# WAY=${PREF}clock [root@aminglinux_01 test]# FAKE=${PREF}feit [root@aminglinux_01 test]# echo $WAY $FAKE counterclock counterfeit
Bourne Again Shell使用特殊的變量$1、$2、$3直到$9,通過位置參數(shù)引用命令行中的參數(shù)。如果需要引用第9個(gè)以后的參數(shù),就必須使用花括號(hào):${10}。命令的名字保存在$0中。
unset:刪除變量
可以使用內(nèi)置命令readonly確保某個(gè)變量的值不被改變。
[root@aminglinux_01 test]# person=jenny [root@aminglinux_01 test]# echo $person jenny [root@aminglinux_01 test]# readonly person [root@aminglinux_01 test]# person=alex -bash: person: 只讀變量
當(dāng)不帶參數(shù)使用內(nèi)置命令readonly時(shí),它會(huì)顯示所有只讀變量的列表。
[root@aminglinux_01 test]# readonly declare -r BASHOPTS="checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath" declare -ir BASHPID declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")' declare -ir EUID="0" declare -ir PPID="1018" declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor" declare -ir UID="0" declare -r person="jenny"
內(nèi)置命令 declare 和 typeset(這是同一個(gè)命令的兩個(gè)名字)可以用來設(shè)置 shell 變量的屬性和值。下表列出了5種屬性。 | 屬性 | 含義 |
---|---|---|
-a | 聲明一個(gè)數(shù)組變量 | |
-f | 聲明一個(gè)函數(shù)名變量 | |
-i | 聲明一個(gè)整型變量 | |
-r | 聲明變量為只讀,也可使用 readonly | |
-x | 輸出變量(設(shè)置為全局變量),也可用 export |
列出變量屬性:如果不帶任何參數(shù)或者選項(xiàng),那么內(nèi)置命令 declare 將列出所有 shell 變量。不帶任何參數(shù)運(yùn)行 set 命令,也會(huì)得到同樣結(jié)果。如果內(nèi)置命令 declare 帶有選項(xiàng),但是沒有變量名作為參數(shù),那么該命令將列出所有具有指定屬性集合的 shell 變量。
關(guān)鍵字變量既可以通過繼承而來,也可以在 shell 啟動(dòng)時(shí)聲明并初始化。
默認(rèn)情況下,用戶主目錄就是用戶登錄之后的工作目錄。當(dāng)用戶創(chuàng)建其賬號(hào)時(shí),其主目錄就已經(jīng)創(chuàng)建下來了,這個(gè)文件名存放在 /etc/passwd 中。
[root@aminglinux_01 test]# grep root /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin
代字符(~):shell 使用 HOME 的值來展開路徑名,該路徑名使用簡(jiǎn)寫形式(代字符 ~ )來表示用戶的主目錄
[root@aminglinux_01 test]# cd [root@aminglinux_01 ~]# pwd /root [root@aminglinux_01 ~]# echo ~ /root
在向 shell 中輸入一個(gè)絕對(duì)路徑名或者相對(duì)路徑名,而不是一個(gè)簡(jiǎn)單的文件名作為命令時(shí),shell 就會(huì)在指定的這個(gè)目錄下,用指定文件名查找可執(zhí)行文件。如果該路徑名對(duì)應(yīng)的文件不存在,shell 將會(huì)報(bào)告“ command not found ”(命令找不到)錯(cuò)誤。如果指定文件存在,但是用戶沒有執(zhí)行權(quán)限,或者是用戶沒有 shell 腳本的讀權(quán)限和執(zhí)行權(quán)限,shell 將報(bào)告“ Permission denied ”(權(quán)限禁止)錯(cuò)誤。
如果使用簡(jiǎn)單的文件名作為命令,shell 將搜索某些目錄,以查找用戶想要執(zhí)行的程序。shell 在幾個(gè)目錄中搜索文件,查找與該命令具有相同的名字、且用戶具有執(zhí)行權(quán)限(對(duì)于編譯好的程序)或者具有讀權(quán)限和執(zhí)行權(quán)限(對(duì)于shell 腳本)的文件。shell 變量 PATH 控制著這些搜索路徑。
[root@QUFENGBIN ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/mysql/bin:/usr/local/openssl/bin:/root/bin
變量 MAIL 包含了保存用戶郵件的文件的路徑名。保存用戶郵件的文件就是該用戶的 mailbox ,通常是 /var/spool/mail/name ,其中 name 是用戶的登錄名。如果設(shè)置了 MAIL 但是沒有設(shè)置 MAILPATH,那么郵件到達(dá) MAIL 指定的文件時(shí),shell 將提醒用戶。
變量 MAILPATH 包含了一個(gè)用冒號(hào)隔開的文件名列表。如果設(shè)置了這個(gè)變量,那么當(dāng)這個(gè)列表中的任何一個(gè)文件發(fā)生改變的時(shí)候(比如郵件到達(dá)時(shí)),shell 都將提醒用戶??梢栽谠摿斜碇腥魏我粋€(gè)文件名后面加上一個(gè)問號(hào)(?),問號(hào)后面跟著一條消息。如果有新郵件,shell 就會(huì)顯示該消息。它取代了用戶登錄系統(tǒng)時(shí)因有郵件而出現(xiàn)的“ you have mail ”消息。
變量 MAILCHECK 規(guī)定了shell以多大的額度(以秒計(jì))檢查新郵件。默認(rèn)值是60秒。如果將該值設(shè)置為0,shell 將在顯示每個(gè)提示符之前檢查新郵件。
[root@QUFENGBIN ~]# echo $MAIL /var/spool/mail/root [root@QUFENGBIN ~]# echo $MAILPATH [root@QUFENGBIN ~]# echo $MAILCHECK 60
Bourne Again Shell 默認(rèn)提示符是一個(gè)美元符號(hào)($)。如果以 root 身份運(yùn)行 bash ,那么提示符是 # 號(hào)。變量 PS1 保存了 shell 用來提示用戶輸入命令的提示符串。當(dāng)用戶修改 PS1 的值時(shí),用戶的提示符就會(huì)發(fā)生改變。
[root@QUFENGBIN ~]# echo $PS1 [\u@\h \W]\$ [root@QUFENGBIN ~]# PS1="[\u@\h \W \!]$ " [root@QUFENGBIN ~ 7]$
PS1="[\u@\h \W !]$ "顯示的提示符的格式為[user@host directory event]$,其中user是用戶名,host為本機(jī)域名中第1個(gè)點(diǎn)號(hào)(.)之前的主機(jī)名,directory為工作目錄的基名,event為當(dāng)前命令的事件編號(hào)。
[root@QUFENGBIN ~ 11]$ PS1="\h \$" QUFENGBIN $PS1="\@ \u $ " 10:45 AM root $ PS1="\$ " $
下表給出了一些 PS1 符號(hào) | 符號(hào) | 在提示符中的顯示 |
---|---|---|
\$ | 如果以root身份運(yùn)行,就顯示為#,否則就是$ | |
\w | 工作目錄的路徑名 | |
\W | 工作目錄的基名 | |
\! | 當(dāng)前事件(歷史)編號(hào) | |
\d | 按照“工作日/月/日期”格式顯示的日期 | |
\h | 機(jī)器的主機(jī)名,不包括域名 | |
\H | 機(jī)器全名,包括域名 | |
\u | 當(dāng)前用戶的用戶名 | |
\@ | 按照“12小時(shí),AM/PM”格式顯示的當(dāng)前時(shí)間 | |
\T | 按照12小時(shí)制“HH:MM:SS”格式顯示當(dāng)前時(shí)間 | |
\A | 按照24小時(shí)制“HH:MM”格式顯示當(dāng)前時(shí)間 | |
\t | 按照24小時(shí)制“HH:MM:SS”格式顯示當(dāng)前時(shí)間 |
[root@QUFENGBIN ~]# echo $PS2 > [root@QUFENGBIN ~ 17]$ echo 'hello world > !!!' hello world !!! [root@QUFENGBIN ~ 18]$ PS2="next: " [root@QUFENGBIN ~ 19]$ echo "hello world next: 2" hello world 2
[root@QUFENGBIN ~]# echo $PS3 [root@QUFENGBIN ~]# echo $PS4 +
IFS(Internet Field Separator,內(nèi)部字段分隔符)shell變量指定了在命令行中用來分隔參數(shù)的字符,其默認(rèn)值為空格符、制表符和換行符。無論IFS的值是什么,用戶總可以使用一個(gè)或者多個(gè)空格符或者制表符分隔命令行中的不同參數(shù),這里假設(shè)這些字符并沒有被引用或者轉(zhuǎn)義。
當(dāng)為IFS指派字符值的時(shí)候,這些字符也可以分隔字段,但是只有在展開的時(shí)候才可以這樣。這種命令行解釋方式稱為分詞(word splitting)。
[root@QUFENGBIN ~]# a=x:y:z [root@QUFENGBIN ~]# cat $a cat: x:y:z: No such file or directory [root@QUFENGBIN ~]# IFS=":" [root@QUFENGBIN ~]# cat $a cat: x: No such file or directory cat: y: No such file or directory cat: z: No such file or directory
shell 根據(jù)在 IFS 中發(fā)現(xiàn)的分隔符劃分命令行中所有被展開的詞。如果不進(jìn)行展開,就不會(huì)進(jìn)行分詞。
[root@QUFENGBIN ~]# IFS="p" [root@QUFENGBIN ~]# export VAR [root@QUFENGBIN ~]# aa=export [root@QUFENGBIN ~]# echo $aa ex ort
盡管連續(xù)出現(xiàn)的多個(gè)空格或制表符被視為一個(gè)分隔符,但是只要出現(xiàn)別的字段分隔符字段,那么每一次出現(xiàn)就被視為一個(gè)分隔符。
使用 CDPATH 變量,用戶可以用一個(gè)簡(jiǎn)單的文件名作為參數(shù)傳遞給內(nèi)置命令 cd ,就將工作目錄改變到某個(gè)目錄,而這個(gè)目錄并不是工作目錄的子目錄。
如果沒有設(shè)置 CDPATH,而只是指定了一個(gè)簡(jiǎn)單的文件名作為調(diào)用 cd 的參數(shù),那么 cd 將在工作目錄中查找具有與該參數(shù)相同的文件名的子目錄。而如果設(shè)置了 CDPATH,cd 將在 CDPATH 列表中的目錄搜索具有與該參數(shù)相同的文件名的子目錄。如果 cd 找到了一個(gè)子目錄,那么該目錄就成為工作目錄。
如果 CDPATH 中沒有包含工作目錄,并且在 CDPATH 中均搜索失敗,那么 cd 將在工作目錄下搜索。如果希望 cd 首先搜索工作目錄,那么可將空字符串作為 CDPATH 的第1項(xiàng)??兆址脙蓚€(gè)冒號(hào)(::)表示。如果內(nèi)置命令cd 的參數(shù)是一個(gè)絕對(duì)路徑——以斜杠(/)開頭——?jiǎng)t shell 不考慮 CDPATH 。
字符 | 用途 | 字符 | 用途 |
---|---|---|---|
換行符 | 啟動(dòng)命令的執(zhí)行 | ; | 分隔命令 |
() | 將命令分組給子shell執(zhí)行,或者是標(biāo)示函數(shù) | & | 在后臺(tái)執(zhí)行命令 |
| | 管道 | > | 重定向標(biāo)準(zhǔn)輸出 |
>> | 追加標(biāo)準(zhǔn)輸出 | < | 重定向標(biāo)準(zhǔn)輸入 |
<< | Here文檔 | * | 模糊文件引用中的零個(gè)或者多個(gè)字符組成的串 |
? | 模糊文件引用中的任何單個(gè)字符 | \ | 引用后面的字符 |
' | 引用字符串,阻止所有替換 | " | 引用字符串,只允許變量替換和命令替換 |
`...` | 執(zhí)行命令替換 | [] | 模糊文件引用中的字符類別 |
$ | 引用某個(gè)變量 | .(內(nèi)置句點(diǎn)) | 執(zhí)行命令(只在行首) |
# | 開始一行注釋 | {} | 用來封裝函數(shù)體 |
;(內(nèi)置空串) | 返回true | &&(布爾“與”) | 只有左邊的命令成功(返回的退出狀態(tài)值為0)才執(zhí)行右邊的命令 |
||(布爾“或”) | 只有左邊的命令失敗(返回非零退出狀態(tài)值)才執(zhí)行右邊的命令 | !(布爾“非”) | 反轉(zhuǎn)命令的退出狀態(tài)值 |
$() | 執(zhí)行命令替換(優(yōu)先形式) | [] | 計(jì)算算術(shù)表達(dá)式的值 |
進(jìn)程(process)是一條命令在Linux上的執(zhí)行。用戶登錄時(shí)啟動(dòng)的shell與其他一樣,也是一條命令,或者進(jìn)程。當(dāng)用戶在命令行中輸入一個(gè)Linux工具名時(shí),就啟動(dòng)了一個(gè)進(jìn)程。當(dāng)用戶運(yùn)行一個(gè)shell腳本的時(shí)候,系統(tǒng)創(chuàng)建另一個(gè)shell進(jìn)程,并為腳本的每行命令創(chuàng)建另外的進(jìn)程。根據(jù)用戶調(diào)用腳本方式的不同,腳本既可以由當(dāng)前shell運(yùn)行,也可由當(dāng)前shell的一個(gè)子shell運(yùn)行。后一種方式更加普遍。如果用戶輸入一個(gè)shell內(nèi)置命令如cd,此時(shí)系統(tǒng)并不會(huì)創(chuàng)建進(jìn)程。
fork系統(tǒng)調(diào)用:進(jìn)程結(jié)構(gòu)類似于文件結(jié)構(gòu),它也是一個(gè)層次式結(jié)構(gòu),有父進(jìn)程、子進(jìn)程甚至根進(jìn)程(root)。父進(jìn)程可以創(chuàng)建(fork)子進(jìn)程,子進(jìn)程又可以創(chuàng)建其他進(jìn)程。術(shù)語(yǔ)fork,就像道路中的岔道口一樣,將一個(gè)進(jìn)程變成兩個(gè)。創(chuàng)建一個(gè)新的進(jìn)程的系統(tǒng)操作例程(或者系統(tǒng)調(diào)用)叫做fork。
當(dāng)系統(tǒng)啟動(dòng)時(shí),Linux開始執(zhí)行,它首先啟動(dòng)init進(jìn)程。這個(gè)進(jìn)程稱為自發(fā)進(jìn)程(spontaneous process),其PID編號(hào)為1。這個(gè)進(jìn)程在進(jìn)程結(jié)構(gòu)中的地位與文件結(jié)構(gòu)中根目錄的地位相同:它是系統(tǒng)進(jìn)程和所有用戶進(jìn)程的祖先。
用于登錄某個(gè)虛擬控制器終端或在GUI中運(yùn)行終端仿真器時(shí)所啟動(dòng)的默認(rèn)的交互shell,是一個(gè)父shell。在CLI提示符后輸入 /bin/bash 命令或其他等效的 bash 命令時(shí),會(huì)創(chuàng)建一個(gè)新的shell程序。這個(gè)shell程序被稱為子shell(child shell)。子shell也擁有CLI提示符,同樣會(huì)等待命令輸入。運(yùn)行shell腳本也能夠創(chuàng)建出子shell。
可以在一行中指定要依次運(yùn)行的一系列命令。這可以通過命令列表來實(shí)現(xiàn),只需要在命令之間加入分號(hào)(;)即可。
在上面的例子中,所有的命令依次執(zhí)行,不存在任何問題。不過這并不是進(jìn)程列表。命令列表要想成為進(jìn)程列表,這些命令必須包含在括號(hào)里。
盡管多出來的括號(hào)看起來沒有什么太大的不同,但起到的效果確是非同尋常。括號(hào)的加入使命令列表變成了進(jìn)程列表,生成了一個(gè)子shell來執(zhí)行對(duì)應(yīng)的命令。
說明 進(jìn)程列表是一種命令分組(command grouping)。另一種命令分組是將命令放入花括號(hào)中,并在命令列表尾部加上分號(hào)(;)。語(yǔ)法為 { command; } 。使用花括號(hào)進(jìn)行命令分組并不會(huì)像進(jìn)程列表那樣創(chuàng)建出子shell。
要想知道是否生成了子shell,得借助一個(gè)使用了環(huán)境變量的命令。這個(gè)命令就是 echo $BASH_SUBSHELL 。如果該命令返回 0 ,就表明沒有子shell。如果返回1 或者其他更大的數(shù)字,就表明存在子shell。
歷史機(jī)制是一項(xiàng)對(duì)C shell的改造功能,它維護(hù)了用戶最近發(fā)出的命令行(亦稱為事件)的列表。內(nèi)置命令history顯示了歷史列表的內(nèi)容
HISTSIZE變量的值決定了在某次會(huì)話期間歷史列表保存的事件數(shù)目。該值的范圍正常情況下是100到1000。
當(dāng)從shell中退出時(shí),最近執(zhí)行的命令將保存在HISTFILE變量指定的文件中(默認(rèn)是~/.bash_history)。下一次啟動(dòng)shell時(shí),將用這個(gè)文件來初始化歷史列表。變量HISTFILESIZE的值決定了保存在HISTFILE中的歷史行數(shù)(不一定與HISTSIZE相同)。HISTSIZE保存了會(huì)話期間記憶的事件數(shù)目,HISTFILESIZE則保存了會(huì)話之間記憶的數(shù)目,HISTFILE指定了保存歷史列表的文件。
[root@aminglinux_01 ~]# echo $HISTSIZE #在一次會(huì)話期間保存的最大事件數(shù)目 1000 [root@aminglinux_01 ~]# echo $HISTFILE #歷史文件的位置 /root/.bash_history [root@aminglinux_01 ~]# echo $HISTFILESIZE #會(huì)話之間保存的事件最大數(shù)目 1000
事件編號(hào):Bourne Again Shell連續(xù)地為每行命令指派了一個(gè)事件編號(hào)(event number)。如果在PS1中包含“!”,則可以將事件編號(hào)作為bash提示符的一部分顯示出來。
[root@aminglinux_01 ~]# echo $PS1 [\u@\h \W]\$ [root@aminglinux_01 ~]# PS1="[\u@\h \W \!]\$" [root@aminglinux_01 ~ 193]$
輸入history命令可以顯示歷史列表中的事件。事件列表按照最早的事件排在列表頂部的順序排列。
[root@aminglinux_01 ~ 194]$history | tail 185 info bash builtin 186 info bash 187 man bash 188 echo $HISTSIZE 189 echo $HISTFILE 190 echo $HISTFILESIZE 191 echo $PS1 192 PS1="[\u@\h \W \!]\$" 193 history 194 history | tail
可以重新執(zhí)行歷史列表中的任何事件??梢圆捎?種方式來瀏覽、修改和重新執(zhí)行前面已執(zhí)行的命令,即使用內(nèi)置命令fc、使用感嘆號(hào)(!)命令以及Readline庫(kù)(暫不介紹),該庫(kù)使用vi編輯器來編輯和執(zhí)行事件。
!!命令重新執(zhí)行前一個(gè)事件,!\$符號(hào)表示前一個(gè)命令行中最后一個(gè)字??梢允褂檬录慕^對(duì)編號(hào)、相對(duì)編號(hào)或者事件中包含的文本來引用該事件。所有的事件引用(稱為事件標(biāo)志符)均以感嘆號(hào)(!)開頭。感嘆號(hào)后面的一個(gè)或多個(gè)字符指定某個(gè)事件。 事件標(biāo)志符:事件標(biāo)志符指定了命令歷史中的某條命令。如下表: | 標(biāo)志符 | 含義 |
---|---|---|
! | 除非后面緊跟著空格符、換行符、=或者(,否則立即開始某個(gè)歷史事件 | |
!! | 前一個(gè)命令 | |
!n | 歷史列表中編號(hào)為n的命令 | |
!-n | 往前第n條命令 | |
!string | 最近以string開頭的命令行 | |
!?string[?] | 包含string的最近命令行,最后的?是可選的 | |
!# | 當(dāng)前命令(目前敲入的部分) | |
!{event} | event為一個(gè)事件標(biāo)示符?;ɡㄌ?hào)將event與左右的文本隔開。比如,!{-3}3 表示后面跟著3的第3個(gè)最近執(zhí)行的命令 |
[root@aminglinux_01 ~ 205]$ls -l 3.txt -rw-r--r--. 1 root root 25 5月 7 13:18 3.txt [root@aminglinux_01 ~ 206]$!! ls -l 3.txt -rw-r--r--. 1 root root 25 5月 7 13:18 3.txt [root@aminglinux_01 ~ 206]$!205 ls -l 3.txt -rw-r--r--. 1 root root 25 5月 7 13:18 3.txt [root@aminglinux_01 ~ 206]$!-1 ls -l 3.txt -rw-r--r--. 1 root root 25 5月 7 13:18 3.txt [root@aminglinux_01 ~ 206]$history 10 197 fc -l 198 type -a fc 199 ll /usr/bin/fc 200 type -a fc 201 history | tail 202 history 203 history | tail 204 ll 205 ls -l 3.txt 206 history 10 [root@aminglinux_01 ~ 207]$!l ls -l 3.txt -rw-r--r--. 1 root root 25 5月 7 13:18 3.txt [root@aminglinux_01 ~ 208]$!?ll? ll 總用量 8 -rw-r--r--. 1 root root 25 5月 7 13:18 3.txt -rw-------. 1 root root 1418 4月 14 21:55 anaconda-ks.cfg drwxr-xr-x. 2 root root 60 5月 7 15:45 test
字標(biāo)志符(word designator)指定了事件中的某個(gè)字或一組字。如下表: | 字標(biāo)志符 | 含義 |
---|---|---|
n | 第n個(gè)字。一般情況下,字0就是命令名 | |
^ | 第1個(gè)字。(緊隨命令名) | |
$ | 最后那個(gè)字 | |
m-n | 最后那個(gè)字從編號(hào)m到n的所有字,如果忽略m,那么m默認(rèn)為0(0-n) | |
n* | 從第n個(gè)到最后那個(gè)之間的所有字 | |
* | 除命令名之外的所有字。與1*相同 | |
% | 最近的匹配?string?搜索的那個(gè)字 |
這些字的編號(hào)從0開始(命令行上的第一個(gè)字,通常指命令名),接著是1(緊隨命令名的第1個(gè)字),直到n(命令行上的最后一個(gè)字)。
為了指定前一個(gè)事件中某個(gè)特定的字,在事件標(biāo)志符(如!14)后面跟著一個(gè)冒號(hào)和一個(gè)表示該字在這個(gè)命令中的標(biāo)號(hào)。如,!14:3指定了事件14中命令名后第3個(gè)字。使用一個(gè)用連字符隔開的兩個(gè)字標(biāo)志符,可以指定字范圍。
[root@aminglinux_01 ~ 209]$echo 1 2 3 4 5 1 2 3 4 5 [root@aminglinux_01 ~ 210]$echo !209:2 echo 2 2 [root@aminglinux_01 ~ 211]$echo !209:^ echo 1 1 [root@aminglinux_01 ~ 212]$!209:0 !209:$ echo 5 5 [root@aminglinux_01 ~ 213]$echo !209:2-4 echo 2 3 4 2 3 4 [root@aminglinux_01 ~ 214]$!209:0-$ echo 1 2 3 4 5 1 2 3 4 5
如果一個(gè)事件只包含了單個(gè)命令,那么字編號(hào)就與參數(shù)編號(hào)對(duì)應(yīng)。如果事件包含了多條命令,那么對(duì)于第一條之后的命令來說,這種對(duì)應(yīng)關(guān)系不再成立。
[root@aminglinux_01 ~ 215]$!209 ; echo 6 7 8 9 echo 1 2 3 4 5 ; echo 6 7 8 9 1 2 3 4 5 6 7 8 9 [root@aminglinux_01 ~ 216]$echo !215:7 echo echo echo [root@aminglinux_01 ~ 217]$echo !215:4-8 echo 4 5 ; echo 6 4 5 6 [root@aminglinux_01 ~ 218]$echo !215:6-7 echo ; echo [root@aminglinux_01 ~ 219]$echo !$ echo echo echo
有時(shí)候需要改變正要執(zhí)行的命令的某些方面。通過在字標(biāo)志符后面或者事件標(biāo)志符后面(如果沒有字標(biāo)志符)放置一個(gè)或多個(gè)修飾符,就可以修改事件或事件的某個(gè)字。每個(gè)修飾符前面必須有一個(gè)冒號(hào)(:)。
替換修飾符:替換修飾符(substitute modifier)要比其他修飾符復(fù)雜。下面有個(gè)例子:
[root@aminglinux_01 ~ 222]$cad ~/3.txt -bash: cad: 未找到命令 [root@aminglinux_01 ~ 223]$!!:s/cad/cat cat ~/3.txt this is a test test THIS
替換修飾符的語(yǔ)法:[g]s/old/new/
old為原字符串(并非正則表達(dá)式),new表示代替old的那個(gè)字符串。替換修飾符用new替換old的第1次出現(xiàn)。在s前面放上g將造成全局替換,即將old的所有出現(xiàn)都替換掉。
其他修飾符:除替換修飾符外,修飾符還可以對(duì)由事件標(biāo)志符和可選字標(biāo)志符選取的事件部分進(jìn)行簡(jiǎn)單的編輯。可以使用多個(gè)修飾符,彼此之間用冒號(hào)(:)隔開。
[root@aminglinux_01 ~ 227]$ls ~/3.txt /root/3.txt [root@aminglinux_01 ~ 228]$!!:p ls ~/3.txt [root@aminglinux_01 ~ 228]$!!:h:p ls ~
下表列出了除替換修飾符之外的事件修飾符 | 修飾符 | 功能 |
---|---|---|
e(extension) | 刪除掉除文件擴(kuò)展名之外的所有內(nèi)容 | |
h(head) | 刪除路徑名的最后部分 | |
p(print-not) | 顯示命令,但不要執(zhí)行 | |
q(quote) | 引用該替換,以防止對(duì)其進(jìn)行進(jìn)一步的替換 | |
r(root) | 刪除文件擴(kuò)展名 | |
t(tail) | 刪除掉路徑名中除末尾之外的所有元素 | |
x | 與q類似,除了單獨(dú)引用替換中的每個(gè)字 |
shell函數(shù)類似于shell腳本,里面存放了一系列可在稍后執(zhí)行的命令。然而,因?yàn)閟hell將函數(shù)存放在物理內(nèi)存(RAM)而不是磁盤文件中,所以,shell訪問函數(shù)的速度要比訪問腳本的速度快得多。shell還對(duì)函數(shù)預(yù)處理(解析),因此其啟動(dòng)速度也要比腳本快得多。最后,shell函數(shù)的執(zhí)行和調(diào)用是在同一個(gè)shell中進(jìn)行的。
shell函數(shù)的聲明可以放在~/.bash_profile初始化文件中,或者放在使用該函數(shù)的腳本中,又或者直接放在命令行??梢允褂脙?nèi)置命令unset刪除函數(shù)。一旦用戶注銷,shell將不再保持這些函數(shù)。
PS:如果某個(gè)shell變量和函數(shù)名稱相同,那么可用unset刪除shell變量。再次用相同的命令,就會(huì)刪除這個(gè)函數(shù)。
聲明一個(gè)shell函數(shù)的語(yǔ)法如下:
[function] function_name()
{
commands
)
以上就是Shell的本質(zhì)以及用法是怎樣的,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。