溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Shell的本質(zhì)以及用法是怎樣的

發(fā)布時(shí)間:2021-09-26 17:25:54 來源:億速云 閱讀:184 作者:柒染 欄目:系統(tǒng)運(yùn)維

本篇文章給大家分享的是有關(guān)Shell的本質(zhì)以及用法是怎樣的,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

1、shell

要點(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)核。

1.1 命令行

當(dāng)在命令提示符后鍵入命令回車,shell將執(zhí)行相應(yīng)的程序。比如,鍵入ls后回車,shell開始執(zhí)行名為ls的工具。也可讓shell以同樣的方式執(zhí)行其他類型的程序,如shell腳本、應(yīng)用程序或自己編寫的程序。包含命令和參數(shù)的行稱為命令行。命令是指在命令行上鍵入的字符,同時(shí)還指對(duì)應(yīng)動(dòng)作所調(diào)用的程序。

1.1.1 語(yǔ)法

命令行語(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è)連字符(“-”或“--”)。

1.命令名

一些有用的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)。

2.參數(shù)

命令行上,每一串不含空格字符的字符序列稱為記號(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ù)
$0Shell本身的文件名
$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
3.選項(xiàng)

選項(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ì)生成用法消息。

4.選項(xiàng)的合并

當(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)不分前后順序。

5.選項(xiàng)的參數(shù)

有些工具的選項(xiàng)本身也要帶參數(shù)。如,gcc(GUN的c編譯器)的-o選項(xiàng)必須后跟gcc產(chǎn)生的可執(zhí)行文件名,通常選項(xiàng)與其參數(shù)間用空格隔開,如下:

[root@QUFENGBIN ~]# gcc -o prog prog.c
6.以連字符開始的參數(shù)

按照約定,工具的參數(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

1.1.2 處理命令行

當(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處理。

1.分析命令行

當(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
2.絕對(duì)路徑名與相對(duì)路徑名

當(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è)定的路徑下搜索。

1.1.3 執(zhí)行命令行

1.進(jìn)程

如果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è)命令的輸入。

2.shell不處理的參數(shù)

由于shell不處理命令行上的參數(shù),只是將它們傳遞給調(diào)用的程序,所以shell不知道選項(xiàng)和參數(shù)是否對(duì)程序有效。所以關(guān)于選項(xiàng)和參數(shù)的錯(cuò)誤消息和用法消息都來自程序自身。也有些命令會(huì)忽略無效的選項(xiàng)。

1.2 標(biāo)準(zhǔn)輸入輸出

標(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ò)誤輸出到哪。

1.2.1 作為文件的屏幕

除了普通文件、目錄文件、硬鏈接和軟鏈接之外,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的路徑名)。

1.2.2 作為標(biāo)準(zhǔn)輸入的鍵盤和作為標(biāo)準(zhǔn)輸出的屏幕

當(dāng)?shù)谝淮蔚卿洉r(shí),shell將其標(biāo)準(zhǔn)輸出發(fā)送到代表屏幕的設(shè)備文件中,采用這種方式輸出可以把輸出內(nèi)容在屏幕上顯示出來。shell還將代表鍵盤的設(shè)備文件作為標(biāo)準(zhǔn)輸入的來源,這樣命令會(huì)把在鍵盤上鍵入的任何內(nèi)容作為輸入接收。

1.2.3 重定向

重定向(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)。

1.重定向標(biāo)準(zhǔn)輸出

通過重定向符號(hào)(>)可以將shell命令的輸出重定向到指定的文件而不再是屏幕。重定向的命令格式為:

command [arguments] >filename

其中,command為可執(zhí)行程序(如應(yīng)用程序或者是工具),arguments是可選參數(shù),filename是shell要重定向輸出到的普通文件名。
重定向可能覆蓋文件!在重定向命令執(zhí)行前,如果該文件已經(jīng)存在,那么shell將重寫并覆蓋其原來的內(nèi)容。

2.重定向標(biāo)準(zhǔn)輸入

與重定向標(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)。

3.noclobber:避免文件的重寫

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
4.向文件追加標(biāo)準(zhǔn)輸出

使用追加輸出符號(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
5./dev/null:使數(shù)據(jù)消失

設(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

1.2.4 管道

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)

1.3 在后臺(tái)運(yùn)行程序

前臺(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è)的命令行。

1.將作業(yè)從前臺(tái)移至后臺(tái)

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)。

2.kill:終止后臺(tái)作業(yè)

命令行上輸入kill后跟進(jìn)程的PID號(hào)(或者后跟%和作業(yè)編號(hào)),可以將后臺(tái)正在運(yùn)行的進(jìn)程(或作業(yè))終止,使用中斷鍵(通常CONTROL+C)是不能實(shí)現(xiàn)其功能的。

1.4 文件名生成/路徑名展開

通配符和通配:當(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)。

1.4.1 特殊字符?

問號(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)

1.4.2 特殊字符*

星號(hào)(*)的功能與問號(hào)的類似,不同之處在于,星號(hào)可以跟文件名中的任意多個(gè)(包括0個(gè))字符匹配。

1.4.3 特殊字符[]

用方括號(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]*

1.5 內(nèi)置命令(內(nèi)建命令)

外部命令
外部命令,有時(shí)候也被稱為文件系統(tǒng)命令,是存在于bash shell之外的程序。它們并不是shell程序的一部分。外部命令程序通常位于/bin、/usr/bin、/sbin或/usr/sbin中。ps是一個(gè)外部命令,你可以使用which和type命令找到它。
Shell的本質(zhì)以及用法是怎樣的
當(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)容。

2、Bourne Again Shell

要點(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腳本文件中的命令。

2.1 shell基礎(chǔ)

內(nèi)容包括編寫和使用初始化文件、重定向標(biāo)準(zhǔn)錯(cuò)誤輸出、編寫和執(zhí)行簡(jiǎn)單的shell腳本、命令分割和分組、實(shí)現(xiàn)作業(yè)控制和操作目錄棧。

2.1.1 初始化文件

當(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)限。

1.登錄shell

登錄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í)文件)常用到的命令。

2.交互式非登錄shell

在交互式非登錄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中的命令。

3.非交互式shell

非交互式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í)行由該變量命名的文件中的命令。

4.建立初始化文件

盡管有很多種初始化文件和shell,但是用戶通常只需要主目錄下的.bash_profile和.bashrc文件。.bash_profile中通過以下命令將為登錄shell執(zhí)行.bashrc(如果該文件存在)中的命令。

if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi
5..(句點(diǎn))或者source:在當(dāng)前shell中運(yùn)行初始化文件

在編輯諸如.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中起作用。

2.1.2 符號(hào)命令

Bourne Again Shell以多種方式使用符號(hào)(、)、[、]和$。為了避免混淆,下表列出了每種符號(hào)最通用的用法。
符號(hào)命令
()子shell
$()命令替換
(())算術(shù)表達(dá)式計(jì)算,let的同義詞(當(dāng)被括起來的值中包含等號(hào)時(shí)使用)
$(())算術(shù)展開(不用于被括起來的值中包含等號(hào)的情形)
[]test命令
[[]]條件表達(dá)式,類似于[],但是添加了字符串比較

2.1.3 重定向標(biāo)準(zhǔn)錯(cuò)誤輸出

除了標(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)

2.1.4 編寫一個(gè)簡(jiǎn)單的shell腳本

shell 腳本是包含 shell 可執(zhí)行命令的文件。shell 腳本中的命令可以是用戶在 shell 提示符后面輸入的任何命令。除了可以使用用戶在命令行下面輸入的命令之外,shell 腳本還可以使用控制流(control flow)命令(亦稱為控制結(jié)構(gòu)(control structure))。使用這組命令可以改變腳本中命令的執(zhí)行順序。

1.chmod:使文件可執(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)
2.#! 指定shell

在 shell 腳本文件的第一行可以放置一行特殊的字符串,告訴操作系統(tǒng)使用哪個(gè) shell 來執(zhí)行這個(gè)文件。因?yàn)椴僮飨到y(tǒng)在試圖 exec 文件之前檢查該程序的開頭字符串,這些字符讓操作系統(tǒng)不必進(jìn)行失敗的嘗試。如果腳本的前兩個(gè)字符是 #! ,那么系統(tǒng)將這兩個(gè)字符后面的那些字符作為用來執(zhí)行該腳本的命令解釋器的絕對(duì)路徑名。它可以是任何程序的路徑名,而不僅僅是 shell 。

3.#開始一行注釋
4.執(zhí)行 shell 腳本(fork、exec、source)

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)行腳本中的命令。

5.fork、exec、source 區(qū)別

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

2.2 參數(shù)和變量

什么是環(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ù)賦值。

2.2.1 用戶創(chuàng)建的變量/引用變量

[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:刪除變量

2.2.2 變量屬性

1. readonly :使變量值不可更改

可以使用內(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"
2. declare 和 typeset :為變量賦予屬性
內(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 變量。

2.2.3 關(guān)鍵字變量

關(guān)鍵字變量既可以通過繼承而來,也可以在 shell 啟動(dòng)時(shí)聲明并初始化。

1. HOME : 用戶主目錄

默認(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
2. PATH :shell 查找程序的路徑

在向 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
3. MAIL :保存電子郵件的地方

變量 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
4. PS1 :用戶主提示符

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í)間
5. PS2 :用戶次提示符
[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
6. PS3 :菜單提示符、PS4 :調(diào)試提示符
[root@QUFENGBIN ~]# echo $PS3

[root@QUFENGBIN ~]# echo $PS4
+
7. IFS :分隔輸入字段(分詞)

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è)分隔符。

8. CDPATH :擴(kuò)大cd的范圍

使用 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 。

2.2.4 shell特殊變量

2.3 特殊字符(待補(bǔ)充)

字符用途字符用途
換行符啟動(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á)式的值

2.4 進(jìn)程

進(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)程。

2.4.1 進(jìn)程結(jié)構(gòu)

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)程的祖先。

2.4.2 shell的父子關(guā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。

2.4.3 進(jìn)程列表

可以在一行中指定要依次運(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。

2.5 命令歷史機(jī)制

歷史機(jī)制是一項(xiàng)對(duì)C shell的改造功能,它維護(hù)了用戶最近發(fā)出的命令行(亦稱為事件)的列表。內(nèi)置命令history顯示了歷史列表的內(nèi)容

2.5.1 控制歷史機(jī)制的變量

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

2.5.2 重新執(zhí)行和編輯命令

可以重新執(zhí)行歷史列表中的任何事件??梢圆捎?種方式來瀏覽、修改和重新執(zhí)行前面已執(zhí)行的命令,即使用內(nèi)置命令fc、使用感嘆號(hào)(!)命令以及Readline庫(kù)(暫不介紹),該庫(kù)使用vi編輯器來編輯和執(zhí)行事件。

1. fc:顯示、編輯和重新執(zhí)行命令
2. 使用感嘆號(hào)(!)引用事件
!!命令重新執(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
3. 字標(biāo)志符
字標(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
4. 修飾符

有時(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è)字

2.6 函數(shù)

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è)資訊頻道。

向AI問一下細(xì)節(jié)

免責(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)容。

AI