<<<作用
* cmd <<< word
把word字符串(而不是文件word)和后面的換行作為輸入提供給cmd。
例如:
[root@snow zc]# cat <<< "hello" > 123.txt
[root@snow zc]# ls
123.txt perl5 word zc.sh
[root@snow zc]# cat 123.txt
hello
[root@snow zc]# : >123.txt 冒號后面有空格,: > 代表清空123.txt文件
[root@snow zc]# cat 123.txt
[root@snow zc]#
冒號作用
{str:=expr}
如果變量str不為空,${str:=expr}就等于str的值,若str為空,就把expr的值賦值給str。
例如:
[root@localhost ~]# ${abc:=t1}
-bash: t1: command not found
[root@localhost ~]# : ${abc:=t1} 冒號后面有空格
[root@localhost ~]# echo $abc
t1
[root@localhost ~]# echo $?
0
注釋:
在第一條賦值命令中,若abc為空,則將t1賦值給abc,同時將t1作為命令來執行,但是并沒有t1這個命令故報錯。
在第二條賦值命令中,若abc為空,則將t1賦值給abc,同時將t1作為參數傳遞給:空命令執行,且返回值為0。
作用一: 占位符
#!/bin/bash
var=0
if [ "$var" = "0" ]; then
:
else
:
fi
作用二: 空命令,與內建的true相同
#!/bin/bash
while :
do
echo "dead loop..."
done
作用三: 與>結合結合使用,用于清空文件
[root@localhost ~#] : > data.log # 清空文件
[root@localhost ~#] cat /dev/null > data.log # 等同于于這種
示例二 清空文件
[root@node56 ~]# cat <<<"Hello" >123.txt
[root@node56 ~]# cat 123.txt
Hello
[root@node56 ~]# : >123.txt
[root@node56 ~]# cat 123.txt
[root@node56 ~]#
作用四: 注釋
單行注釋
: your comment here 冒號后面有空格
等價于
# your comment here
多行注釋
: 'comment line1 冒號后面有空格
comment line2
more comments'
例如:
: this is single line comment 冒號后面有空格
: 'this is a multiline comment, 冒號后面有空格
second line
end of comments'
示例三 腳本注釋、占位符
腳本test_colon.sh
#!/bin/sh
: this is single line comment 腳本注釋
: 'this is a multiline comment, 腳本注釋
second line
end of comments'
if [ "1" == "1" ]; then
echo "yes"
else
: 占位符
fi
點號作用
想在當前shell腳本中,調用另外一個shell庫里面的函數,可以使用點號(.)或者source命令。
例如:
[root@snow zc]# cat lss.sh
#!/bin/bash
ls -al
echo
echo
. /home/zc/zc.sh 點號(.)后面有空格,且是絕對路徑
[root@snow zc]#
source命令的作用就是用來執行一個腳本,那么: source a.sh 同直接執行 ./a.sh 有什么不同呢? 比如您在一個腳本里export $KKK=111,假如您用./a.sh執行該腳本,執行完畢后,您運行echo $KKK,發現沒有值, 假如您用source來執行,然后再echo ,就會發現KKK=111。因為調用./a.sh來執行shell是在一個子shell里運行的, 所以執行后,結果并沒有反應到父shell里,但是source不同他就是在本shell中執行的,所以能夠看到結果。
經典問題:
shell腳本(test.sh)如下:
#!/bin/sh
echo "export monitor=1" >> /etc/profile
source /etc/profile
調用后(./test.sh),執行echo $monitor,沒有輸出任何值
手動source /etc/profile后,再次執行echo $monitor,輸出了預期的值
可見腳本中的source /etc/profile沒有成功(提法本身就是錯誤的),請問這個應該怎么解決?
A:在執行test.sh的時候,不用./test.sh
用source test.sh。
alias實現命令別名
1.顯示當前設置的所有別名:
[root@snow zc]# alias
alias cdp='cd /root/zhangchao'
alias cdz='cd /home/zc'
alias cp='cp -i'
2.只顯示某個別名代表的含義可輸入alias name
[root@snow zc]# alias ll
alias ll='ls -l --color=auto'
[root@snow zc]#
3.為命令設置別名可輸入alias 新命令='原命令 選項/參數'
[root@snow zc]# alias cdz='cd /home/zc'
4.取消命令別名
[root@snow zc]# unalias ll
5.一次執行多個命令
a.首先使用命令 type 自定義命令名 ,查看自定義命令名是否被系統占用。
[root@snow zc]# type ll
ll is aliased to `ls -l --color=auto'
[root@snow zc]# type loo
-bash: type: loo: not found
[root@snow zc]#
b.使用命令alias創建自定義命令:alias loo='cd /root;ls;cd /' 。需要注意的是命令的使用格式,分號與分號之間是沒有空格的。
c.如果希望刪除這個自定義命令,可以使用命令 unalias 自定義命令名 來完成
6.別名永久生效
那就是修改rc配置文件,把設置別名的過程加入到系統啟動后初始化用戶的腳本中, 用戶只需要修改 ~/.bashrc文件, 加入你要設置的別名命令即可
想要添加一個命令 oo 輸入oo就能直接進入/mnt/hgfs/D/work/project/ASID/5.code/trunk/ASID/ASID/wms目錄
方法:vi /etc/bashrc
在文件末尾添加alias oo='cd /mnt/hgfs/D/work/project/ASID/5.code/trunk/ASID/ASID/wms/'并保存退出
執行source /etc/bashrc 使配置生效
完成!
bg、fg bg %num 即可將掛起的job的狀態由stopped改為running,仍在后臺執行;
當需要改為在前臺執行時,執行命令fg %num即可;
builtin命令
用以執行shell的內建命令,既然是內建命令,為什么還要以這種方式執行呢?因為shell命令執行時首先從函數開始,如果自定義了一個與內建命令同名的函數,那么就執行這個函數而非真正的內建命令。
$ umask
0002
$ umask() { echo "umask function"; }
$ umask
umask function
$ builtin umask
0002
$ unset -f umask
$ umask
0002
caller命令 返回當前活動的子程序調用的上下文,即調用堆棧信息,包括shell函數和內建命令source執行的腳本。 沒有指定expr時,顯示當前子程序調用的行號和源文件名。如果expr是一個非負整數,顯示當前子程序調用的行號、子程序名和源文件名。 caller命令打印出來的堆棧信息在調試程序時是很有幫助的,當前棧幀為0。如果shell沒有子程序調用或者expr是一個無效的位置時,call命令返回false。
caller一般做調試用,打印出函數調用的行號和源文件名。
例如:
foo()
{
echo "foo called"
caller
}
bar()
{
echo "bar called"
caller 0
}
test1()
{
echo "test1 called"
caller
caller 0
caller 1
caller 2
}
test2()
{
echo "test2 called"
test1
}
test3()
{
echo "test3 called"
test2
}
foo
bar
test3
command命令
類似于builtin,也是為了避免調用同名的shell函數,命令包括shell內建命令和環境變量PATH中的命令。選項“-p”指定在默認的環境變量PATH中查找命令路徑。選項“-v”和“-V”用于顯示命令的描述,后者顯示的信息更詳細。
例如:
[root@snow zc]# ps
PID TTY TIME CMD
5826 pts/0 00:00:00 bash
7019 pts/0 00:00:00 ps
[root@snow zc]#
[root@snow zc]# ps() { echo "function ps"; }
[root@snow zc]# ps
function ps
[root@snow zc]# builtin ps ps不是內建命令,是環境變量命令
-bash: builtin: ps: not a shell builtin
[root@snow zc]# command ps
PID TTY TIME CMD
5826 pts/0 00:00:00 bash
7020 pts/0 00:00:00 ps
[root@snow zc]#
disown 后臺掛載,在后臺運行用戶進程,不受shell退出的影響,彌補沒有使用&和nuhup。
disown 使已經在運行的用戶進程 不受用戶退出限制
disown -h %1 # 1 為jobsID
如果已經在當前終端運行 ;可以ctrl+z 掛起 ;bg jobsID 放入后臺
disown -h jobsID #使已經在運行的用戶進程 不受用戶退出限制
用disown -h jobspec來使某個作業忽略HUP信號。
用disown -ah 來使所有的作業都忽略HUP信號。
用disown -rh 來使正在運行的作業忽略HUP信號。
需要注意的是,當使用過 disown 之后,會將把目標作業從作業列表中移除,我們將不能再使用jobs來查看它,但是依然能夠用ps -ef查找到它。
disown命令可以從當前shell的作業列表中移除全部作業,也可移除指定的一到多個作業;正在運行的作業也可以移除;也可以標記作業,使得它們在當前shell退出后也不會結束。
該命令需要set選項monitor處于開啟狀態時才能執行;查看作業控制狀態:輸入set -o查看 monitor行;執行set -o monitor或set -m開啟該選項。 disown命令該命令是bash內建命令,相關的幫助信息請查看help命令。
語法格式
disown [參數] [標識符or進程ID]
常用參數:
-h 標記每個作業標識符,這些作業將不會在shell接收到sighup信號時接收到sighup信號
-a 移除所有的作業
-r 移除運行的作業
參考實例
刪除全部作業:
[root@linux265 ~]# disown -a
刪除運行狀態的作業:
[root@linux265 ~]# disown -r
根據jobId,移出指定的后臺任務:
[root@linux265 ~]# disown -h %2
一、鍵入不同
1、HUP中斷信號:HUP中斷信號是當用戶鍵入<Ctrl+X>時由終端驅動程序發送的信號。
2、INT中斷信號:INT中斷信號是當用戶鍵入<Ctrl+I>時由終端驅動程序發送的信號。
3、KILL中斷信號:KILL中斷信號是當用戶鍵入<Ctrl+Z>時由終端驅動程序發送的信號。
4、TERM中斷信號:TERM中斷信號是當用戶鍵入<Ctrl+ >時由終端驅動程序發送的信號。
5、TSTP中斷信號:TSTP中斷信號是當用戶鍵入<Ctrl+T>時由終端驅動程序發送的信號。二、二、對應操作不同
1、HUP中斷信號:HUP中斷信號的對應操作為讓進程掛起,睡眠。
2、INT中斷信號:INT中斷信號的對應操作為正常關閉所有進程。
3、KILL中斷信號:KILL中斷信號的對應操作為強制關閉所有進程。
4、TERM中斷信號:TERM中斷信號的對應操作為正常的退出進程。
5、TSTP中斷信號:TSTP中斷信號的對應操作為暫時停用進程。
三、啟用不同
1、HUP中斷信號:HUP中斷信號發送后,可以重新被用戶再次輸入恢復啟用進程。
2、INT中斷信號:INT中斷信號發送后,不可以重新被用戶再次輸入恢復啟用進程。
3、KILL中斷信號:KILL中斷信號發送后,不可以重新被用戶再次輸入恢復啟用進程。
4、TERM中斷信號:TERM中斷信號發送后,可以重新被用戶再次輸入啟用進程。
5、TSTP中斷信號:TSTP中斷信號發送后,可以重新被用戶再次輸入繼續使用進程。
enable命令
用于啟動或關閉 shell 內建指令。
若要執行的文件名稱與shell內建指令相同,可用enable -n來關閉shell內建指令。若不加-n參數,enable可重新啟動關閉的指令。
eval
eval主要用在對參數的特殊處理上面的,一般的命令行,shell處理參數就只執行一遍,像轉義和變量轉變; 但加上eval后就可以對參數經行兩遍處理;網上有說是對command-line處理兩遍,我認為是不合理的。 一個eval只能使shell對參數多一次處理,因此有幾個eval就可以多加幾次,即eval eval command-line 這樣就能對參數進行三次編譯,但此時應特別注意參數的轉義,下面有例子說明。
eval命令會計算(evalue)它的參數,這些參數作為表達式計算后重新組合為一個字符串,然后作為一個命令被執行。
eval最常見的用法是將動態生成的命令行計算并執行。例如:
$ name=woodie
$ cmd="echo Helllo $name! "
$ eval $cmd
Hello woodie!
[root@localhost simon]#vim a.sh
#!/bin/bash
echo "$$#" 進程號+#
echo "$$#" $+參數個數
eval echo "$$#" 最后一個參數值
[root@localhost simon]#./a.sh w s d
20621#
$3
d
exec 命令 命令代替shell程序,命令退出,shell 退出;比如 exec ls
這個命令還可以作為find命令的一個選項,如下所示:
(1)在當前目錄下(包含子目錄),查找所有txt文件并找出含有字符串"bin"的行
find ./ -name "*.txt" -exec grep "bin" {} ;
(2)在當前目錄下(包含子目錄),刪除所有txt文件
find ./ -name "*.txt" -exec rm {} ;
shell 中的 exec 兩種用法:
1.exec 命令 ;命令代替shell程序,命令退出,shell 退出;比如 exec ls
2.exec 文件重定向,可以將文件的重定向就看為是shell程序的文件重定向 比如 exec 5</dev/null;exec 5<&-
shell的內建命令exec將并不啟動新的shell,而是用要被執行命令替換當前的shell進程,并且將老進程的環境清理掉,而且exec命令后的其它命令將不再執行。
因此,如果你在一個shell里面,執行exec ls那么,當列出了當前目錄后,這個shell就自己退出了,因為這個shell進程已被替換為僅僅執行ls命令的一個進程,執行結束自然也就退出了。 為了避免這個影響我們的使用,一般將exec命令放到一個shell腳本里面,用主腳本調用這個腳本,調用點處可以用bash a.sh,(a.sh就是存放該命令的腳本), 這樣會為a.sh建立一個sub shell去執行,當執行到exec后,該子腳本進程就被替換成了相應的exec的命令。
source命令或者".",不會為腳本新建shell,而只是將腳本包含的命令在當前shell執行。
不過,要注意一個例外,當exec命令來對文件描述符操作的時候,就不會替換shell,而且操作完成后,還會繼續執行接下來的命令。
exec 3<&0:這個命令就是將操作符3也指向標準輸入。
另外,這個命令還可以作為find命令的一個選項,如下所示:
(1)在當前目錄下(包含子目錄),查找所有txt文件并找出含有字符串"bin"的行
find ./ -name "*.txt" -exec grep "bin" {} ;
(2)在當前目錄下(包含子目錄),刪除所有txt文件
find ./ -name "*.txt" -exec rm {} ;
先總結一個表:
exec命令 作用
exec ls 在shell中執行ls,ls結束后不返回原來的shell中了
exec <file 將file中的內容作為exec的標準輸入
exec >file 將file中的內容作為標準寫出
exec 3<file 將file讀入到fd3中
sort <&3 fd3中讀入的內容被分類
exec 4>file 將寫入fd4中的內容寫入file中
ls >&4 Ls將不會有顯示,直接寫入fd4中了,即上面的file中
exec 5<&4 創建fd4的拷貝fd5
exec 3<&- 關閉fd3
1. exec 執行程序
雖然exec和source都是在父進程中直接執行,但exec這個與source有很大的區別,source是執行shell腳本,而且執行后會返回以前的shell。 而exec的執行不會返回以前的shell了,而是直接把以前登陸shell作為一個程序看待,在其上經行復制。
舉例說明:
root@localhost:~/test#exec ls
exp1 exp5 linux-2.6.27.54 ngis_post.sh test xen-3.0.1-install
<logout>
root@localhost:~/test#exec >text
root@localhost:~/test#ls
root@localhost:~/test#pwd
root@localhost:~/test#echo "hello"
root@localhost:~/test#exec>/dev/tty
root@localhost:~/test#cat text
exp1
exp5
linux-2.6.27.54
ngis_post.sh
test
text
xen-3.0.1-install
/root/test
hello
root@localhost:~/test#
Exec >text 是將當前shell的標準輸出都打開到text文件中
root@localhost:~/test#cat test
ls
Pwd
root@localhost:~/test#bash
root@localhost:~/test#exec <test
root@localhost:~/test#ls
exp1 exp5 linux-2.6.27.54 ngis_post.sh test text xen-3.0.1-install
root@localhost:~/test#pwd
/root/test
root@localhost:~/test#
root@localhost:~/test#exit #自動執行
2. exec的重定向
先上我們進如/dev/fd/目錄下看一下:
root@localhost:~/test#cd /dev/fd
root@localhost:/dev/fd#ls
0 1 2 255
默認會有這四個項:0是標準輸入,默認是鍵盤。
1是標準輸出,默認是屏幕/dev/tty
2是標準錯誤,默認也是屏幕
255
當我們執行exec 3>test時:
root@localhost:/dev/fd#exec 3>/root/test/test
root@localhost:/dev/fd#ls
0 1 2 255 3
root@localhost:/dev/fd#
看到了吧,多了個3,也就是又增加了一個設備,這里也可以體會下linux設備即文件的理念。 這時候fd3就相當于一個管道了,重定向到fd3中的文件會被寫在test中。關閉這個重定向可以用exec 3>&-。
root@localhost:/dev/fd#who >&3
root@localhost:/dev/fd#ls >&3
root@localhost:/dev/fd#exec 3>&-
root@localhost:/dev/fd#cat /root/test/te
test text
root@localhost:/dev/fd#cat /root/test/test
root tty1 2010-11-16 01:13
root pts/0 2010-11-15 22:01 (192.168.0.1)
root pts/2 2010-11-16 01:02 (192.168.0.1)
0
1
2
255
3
3. 應用舉例:
exec 3<test
while read -u 3 pkg
do
echo "$pkg"
done
. 系統調用exec是以新的進程去代替原來的進程,但進程的PID保持不變。因此,可以這樣認為,exec系統調用并沒有創建新的進程,只是替換了原來進程上下文的內容。 原進程的代碼段,數據段,堆棧段被新的進程所代替。
一個進程主要包括以下幾個方面的內容:
(1)一個可以執行的程序
(2) 與進程相關聯的全部數據(包括變量,內存,緩沖區)
(3)程序上下文(程序計數器PC,保存程序執行的位置)
2. exec是一個函數簇,由6個函數組成,分別是以excl和execv打頭的。
執行exec系統調用,一般都是這樣,用fork()函數新建立一個進程,然后讓進程去執行exec調用。 我們知道,在fork()建立新進程之后,父進各與子進程共享代碼段,但數據空間是分開的,但父進程會把自己數據空間的內容copy到子進程中去,還有上下文也會copy到子進程中去。 而為了提高效率,采用一種寫時copy的策略,即創建子進程的時候,并不copy父進程的地址空間,父子進程擁有共同的地址空間, 只有當子進程需要寫入數據時(如向緩沖區寫入數據),這時候會復制地址空間,復制緩沖區到子進程中去。從而父子進程擁有獨立的地址空間。 而對于fork()之后執行exec后,這種策略能夠很好的提高效率,如果一開始就copy,那么exec之后,子進程的數據會被放棄,被新的進程所代替。
3. exec與system的區別
(1) exec是直接用新的進程去代替原來的程序運行,運行完畢之后不回到原先的程序中去。
(2) system是調用shell執行你的命令,system=fork+exec+waitpid,執行完畢之后,回到原先的程序中去。繼續執行下面的部分。
總之,如果你用exec調用,首先應該fork一個新的進程,然后exec. 而system不需要你fork新進程,已經封裝好了。
exec I/O重定向詳解及應用實例
1、 基本概念(這是理解后面的知識的前提,請務必理解)
a、 I/O重定向通常與 FD有關,shell的FD通常為10個,即 0~9;
b、 常用FD有3個,為0(stdin,標準輸入)、1(stdout,標準輸出)、2(stderr,標準錯誤輸出),默認與keyboard、monitor、monitor有關;
c、 用 來改變送出的數據信道(stdout, stderr),使之輸出到指定的檔案;
e、 0 是 與 1> 是一樣的;
f、 在IO重定向 中,stdout 與 stderr 的管道會先準備好,才會從 stdin 讀進資料;
g、 管道“|”(pipe line):上一個命令的 stdout 接到下一個命令的 stdin;
h、 tee 命令是在不影響原本 I/O 的情況下,將 stdout 復制一份到檔案去;
i、 bash(ksh)執行命令的過程:分析命令-變量求值-命令替代(``和$( ))-重定向-通配符展開-確定路徑-執行命令;
j、 ( ) 將 command group 置于 sub-shell 去執行,也稱 nested sub-shell,它有一點非常重要的特性是: 繼承父shell的Standard input, output, and error plus any other open file descriptors。
k、 exec 命令:常用來替代當前 shell 并重新啟動一個 shell,換句話說,并沒有啟動子 shell。 使用這一命令時任何現有環境都將會被清除。exec 在對文件描述符進行操作的時候,也只有在這時,exec 不會覆蓋你當前的 shell 環境。
2、cmd &n 使用系統調用 dup (2) 復制文件描述符 n 并把結果用作標準輸出
&- 關閉標準輸出
n&- 表示將 n 號輸出關閉
上述所有形式都可以前導一個數字,此時建立的文件描述符由這個數字指定而不是缺省的 0 或 1。如:
... 2>file 運行一個命令并把錯誤輸出(文件描述符 2)定向到 file。
... 2>&1 運行一個命令并把它的標準輸出和輸出合并。(嚴格的說是通過復制文件描述符 1 來建立文件描述符 2 ,但效果通常是合并了兩個流。)
我們對 2>&1詳細說明一下 :2>&1 也就是 FD2=FD1 ,這里并不是說FD2 的值 等于FD1的值,因為 > 是改變送出的數據信道, 也就是說把 FD2 的 “數據輸出通道” 改為 FD1 的 “數據輸出通道”。如果僅僅這樣,這個改變好像沒有什么作用,因為 FD2 的默認輸出和 FD1的默認輸出本來都是 monitor,一樣的!
但是,當 FD1 是其他文件,甚至是其他 FD 時,這個就具有特殊的用途了。請大家務必理解這一點。
3、 如果 stdin, stdout, stderr 進行了重定向或關閉, 但沒有保存原來的 FD, 可以將其恢復到 default 狀態嗎?
*** 如果關閉了stdin,因為會導致退出,那肯定不能恢復。
*** 如果重定向或關閉 stdout和stderr其中之一,可以恢復,因為他們默認均是送往monitor(但不知會否有其他影響)。 如恢復重定向或關閉的 stdout: exec 1>&2 ,恢復重定向或關閉的stderr:exec 2>&1。
*** 如果stdout和stderr全部都關閉了,又沒有保存原來的FD,可以用:exec 1>/dev/tty 恢復。
4、 cmd >a 2>a 和 cmd >a 2>&1 為什么不同?
cmd >a 2>a :stdout和stderr都直接送往文件 a ,a文件會被打開兩遍,由此導致stdout和stderr互相覆蓋。
cmd >a 2>&1 :stdout直接送往文件a ,stderr是繼承了FD1的管道之后,再被送往文件a 。a文件只被打開一遍,就是FD1將其打開。
我想:他們的不同點在于:
cmd >a 2>a 相當于使用了兩個互相競爭使用文件a的管道;
而cmd >a 2>&1 只使用了一個管道,但在其源頭已經包括了stdout和stderr。
從IO效率上來講,cmd >a 2>&1的效率應該更高!
exec 0exec 1>outfilename # 打開文件outfilename作為stdout
exec 2>errfilename # 打開文件 errfilename作為 stderr
exec 0&- # 關閉 FD1
exec 5>&- # 關閉 FD5
export
Linux export 命令用于設置或顯示環境變量。
在 shell 中執行程序時,shell 會提供一組環境變量。export 可新增,修改或刪除環境變量,供后續執行的程序使用。export 的效力僅限于該次登陸操作。
語法
export [-fnp][變量名稱]=[變量設置值]
參數說明:
-f 代表[變量名稱]中為函數名稱。
-n 刪除指定的變量。變量實際上并未刪除,只是不會輸出到后續指令的執行環境中。
-p 列出所有的shell賦予程序的環境變量。
# export MYENV=7 //定義環境變量并賦值
# export -p
declare -x HOME=“/root“
declare -x LANG=“zh_CN.UTF-8“
declare -x LANGUAGE=“zh_CN:zh“
fc
使用該指令顯示歷史命令,輸入如下命令:
[root@localhost ~]# fc -l -10 #顯示10條歷史命令
1039 type -a grep
1040 export
1041 history 10
hash命令
顯示、添加或清除哈希表>
linux系統下的hash指令:
說明:linux系統下會有一個hash表,當你剛開機時這個hash表為空,每當你執行過一條命令時,hash表會記錄下這條命令的路徑,就相當于緩存一樣。 第一次執行命令shell解釋器默認的會從PATH路徑下尋找該命令的路徑,當你第二次使用該命令時,shell解釋器首先會查看hash表,沒有該命令才會去PATH路徑下尋找。
hash表的作用:大大提高命令的調用速率。
hash的參數:
[root@redhat ~]# hash //輸入hash或hash -l 可以查看hash表的內容,我剛開機所以為空
hash: hash table empty
[root@redhat ~]# hash -l
hash: hash table empty
當我執行過2條命令后再看:
[root@redhat ~]# hash //hash表會記錄下執行該命令的次數,以及命令的絕對路徑
hits command
1 /bin/cat
1 /bin/ls
[root@redhat ~]# hash -l //加參數-l既可以看到hash表命令的路徑,也可以看到它的名字,說不定會有別名哦
builtin hash -p /bin/cat cat
builtin hash -p /bin/ls ls
[root@redhat ~]# hash -p /bin/ls bb //添加hash表,可以看到我把ls命令重新寫了一遍,改名為bb
[root@redhat ~]# bb //當我執行bb時就是執行ls命令
anaconda-ks.cfg icmp_echo_ignore_aly~ pub.key
dead.letter icmp_echo_ignore_alz~ rpmbuild
icmp_echo_ignore_all~ install.log RPM-GPG-KEY-useradd
icmp_echo_ignore_alw~ install.log.syslog RPM-GPG-KEY-westos
icmp_echo_ignore_alx~ passwd
[root@redhat ~]# hash -t ls //-t參數可以查看hash表中命令的路徑,要是hash表中沒有怎么辦?
/bin/ls
[root@redhat ~]# hash -t df //我沒使用過df,執行hash,就會提示找不到該命令
-bash: hash: df: not found
[root@redhat ~]# hash -r //清楚hash表,清楚的是全部的
[root@redhat ~]# hash -l
hash: hash table empty
[root@redhat ~]# hash -l
builtin hash -p /bin/cat cat
builtin hash -p /bin/ls ls
[root@redhat ~]# hash -d cat //清楚其中的某一條
[root@redhat ~]# hash -l
builtin hash -p /bin/ls ls
let
在shell中可以使用let來指示下面是算術表達式,let表達式內變量不用加$
var=1
let "var+=1" 或 let var+=1 這種寫法運算符間不能有空格
echo $var
output:
2
這其中的let可以用(())代替,let ″j=i*6+2″等價于((j=i*6+2)), 就像很多的循環中用法一樣
注意:let必須是完整的算術表達式,即有等號兩邊。(())、expr 可以只有等號右邊的計算,由$((...))、$(expr ...)、`expr ...` 查看返回結果
var=1
((var++)) 查看結果: echo $(())
echo $var
output:
2
mapfile
bash提供了兩個內置命令:readarray和mapfile,它們是同義詞。它們的作用是從標準輸入讀取一行行的數據,然后每一行都賦值給一個數組的各元素。 顯然,在shell編程中更常用的是從文件、從管道讀取,不過也可以從文件描述符中讀取數據。
需要先說明的是,shell并不像其它專門的編程語言對數組、列表提供了大量的操作工具,反而直接操作文本文件更為常見(sed、awk等),所以mapfile用的并不多。
1.語法
mapfile [OPTIONS] ARRAY
readarray [OPTIONS] ARRAY
其中options:
-O INDEX :指定從哪個索引號開始存儲數據,默認存儲數據的起始索引號為0
-n count :最多只拷貝多少行到數組中,如果count=0,則拷貝所有行
-s count :忽略前count行不讀取
-c NUM :每讀取NUM行就調用一次"-C callback"選項指定的callback程序
-C callback:每讀取"-c NUM"選項指定的NUM行就執行一次callback回調程序
-d string :指定讀取數據時的行分隔符,默認是換行符
-t :移除尾隨行分隔符,默認是換行符
-u fd :指定從文件描述符fd而非標準輸入中讀取數據
?如果不指定ARRAY參數,則默認使用數組MAPFILE
?如果不指定"-O"選項,則在存儲數據之前先清空數組(如果該數組已存在)
?給定了"-C callback"卻沒有給定"-c NUM"時,則默認為每5000行調用一次回調程序
?回調程序是在讀取給定行數之后,賦值到數組元素之前執行的。所以流程為:"讀NUM行-->callback-->賦值"
?每次調用回調函數時,都將調用callback之前的最后一行數據及其對應的索引號作為回調程序的參數。 例如-c 3 -C callback,則會將索引號2和第3行內容,索引號5和第6行內容作為callback程序的參數
?"-t"去除行尾分隔符,一般來說都是換行符。用其他語言編程過的人都知道行尾換行符有多煩心,但對于shell編程來說,倒是無所謂
2.幾個示例和注意事項
先創建一個示例用的文件alpha.log,每行一個小寫字母,共26行:
$ echo {a..z} | tr " " "
" >alpha.log
$ cat alpha.log
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
讀取該文件并將每一行存儲到數組myarr中(如果不指定,則存儲到默認的MAPFILE數組中)。
$ mapfile myarr <alpha.log
$ echo ${myarr[@]}
a b c d e f g h i j k l m n o p q r s t u v w x y z
$ echo ${myarr[2]}
c
既然是讀取標準輸入,常見的就有以下幾種讀取形式:
$ mapfile myarr <alpha.log # 1.輸入重定向
$ mapfile myarr < <(cat alpha.log) # 2.進程替換
$ cat alpha.log | mapfile myarr # 3.管道傳遞
第1、2種寫法沒什么問題,但第3種寫法是有問題的。
$ cat alpha.log | mapfile myarr1
$ echo ${#myarr1[@]}
0
從結果中可以看到,myarr1根本就不存在。為什么?我在shell中while循環的陷阱中給出過解釋。這里簡單說明一下,對于管道組合的多個命令, 它們都會放進同一個進程組中,會進入子shell執行相關操作。當執行完畢后,進程組結束,子shell退出。 而子shell中設置的環境是不會粘滯到父shell中的(即不會影響父shell),所以myarr1數組是子shell中的數組,回到父shell就消失了。
解決方法是在子shell中操作數組:
$ cat alpha.log | { mapfile myarr1;echo ${myarr1[@]}; }
readarray命令
用于從標準輸入或選項“-u”指定的文件描述符fd中讀取文本行,然后賦值給索引(下標)數組array,如果不指定數組array,則使用默認的數組名MAPFILE。
下面解釋readarray命令中各選項的作用。
“-n count”:復制最多count行,如果count為0,則復制所有的行。
“-O origin”:從下標位置origin開始對數組賦值,默認為0。
“-s count”:忽略開始讀取的count行。
“-t”:刪除文本行結尾的換行符。
“-u fd”:從文件描述符fd中讀取文本行。
“-C callback”:每當讀取選項“-c”指定的quantum行時(默認為5000行),就執行一次回調callback。
下面以簡單的例子說明readarray命令的用法:
$ readarray foo
hello world
hello bash
^C
$ echo ${foo[@]}
hello world hello bash
$ echo ${#foo[@]}
2
hanjunjie@hanjunjie-HP:~$ echo ${foo[0]}
hello world
hanjunjie@hanjunjie-HP:~$ echo ${foo[1]}
hello bash
set 用來顯示本地變量
env 用來顯示環境變量
export 用來顯示和設置環境變量
set 顯示當前shell的變量,包括當前用戶的變量
env 顯示當前用戶的變量
export 顯示當前導出成用戶變量的shell變量
每個shell有自己特有的變量(set)顯示的變量,這個和用戶變量是不同的,當前用戶變量和你用什么shell無關, 不管你用什么shell都在,比如HOME,SHELL等這些變量,但shell自己的變量不同shell是不同的,比如BASH_ARGC, BASH等, 這些變量只有set才會顯示,是bash特有的,export不加參數的時候,顯示哪些變量被導出成了用戶變量,因為一個shell自己的變量可以通過export “導出”變成一個用戶變量
[root@linux ~]# aaa=bbb
[root@linux ~]# echo $aaa
bbb
[root@linux ~]# set|grep aaa
aaa=bbb
[root@linux ~]# env|grep aaa
[root@linux ~]# export aaa
[root@linux ~]# env|grep aaa
aaa=bbb
Bash Shell 內建命令
命令
說明
:
擴展參數列表,執行重定向操作
.
讀取并執行指定文件中的命令(在當前 shell 環境中)
alias
為指定命令定義一個別名
bg
將作業以后臺模式運行
bind
將鍵盤序列綁定到一個 readline 函數或宏
break
退出 for、while、select 或 until 循環
builtin
執行指定的 shell 內建命令
caller
返回活動子函數調用的上下文
cd
將當前目錄切換為指定的目錄
command
執行指定的命令,無需進行通常的 shell 查找
compgen
為指定單詞生成可能的補全匹配
complete
顯示指定的單詞是如何補全的
compopt
修改指定單詞的補全選項
continue
繼續執行 for、while、select 或 until 循環的下一次迭代
declare
聲明一個變量或變量類型。
dirs
顯示當前存儲目錄的列表
disown
從進程作業表中刪除指定的作業
echo
將指定字符串輸出到 STDOUT
enable
啟用或禁用指定的內建shell命令
eval
將指定的參數拼接成一個命令,然后執行該命令
exec
用指定命令替換 shell 進程
exit
強制 shell 以指定的退出狀態碼退出
export
設置子 shell 進程可用的變量
fc
從歷史記錄中選擇命令列表
fg
將作業以前臺模式運行
getopts
分析指定的位置參數
hash
查找并記住指定命令的全路徑名
help
顯示幫助文件
history
顯示命令歷史記錄
jobs
列出活動作業
kill
向指定的進程 ID(PID) 發送一個系統信號
let
計算一個數學表達式中的每個參數
local
在函數中創建一個作用域受限的變量
logout
退出登錄 shell
mapfile
從 STDIN 讀取數據行,并將其加入索引數組
popd
從目錄棧中刪除記錄
printf
使用格式化字符串顯示文本
pushd
向目錄棧添加一個目錄
pwd
顯示當前工作目錄的路徑名
read
從 STDIN 讀取一行數據并將其賦給一個變量
readarray
從 STDIN 讀取數據行并將其放入索引數組
readonly
從 STDIN 讀取一行數據并將其賦給一個不可修改的變量
return
強制函數以某個值退出,這個值可以被調用腳本提取
set
設置并顯示環境變量的值和 shell 屬性
shift
將位置參數依次向下降一個位置
shopt
打開/關閉控制 shell 可選行為的變量值
source
讀取并執行指定文件中的命令(在當前 shell 環境中)
suspend
暫停 Shell 的執行,直到收到一個 SIGCONT 信號
test
基于指定條件返回退出狀態碼 0 或 1
times
顯示累計的用戶和系統時間
trap
如果收到了指定的系統信號,執行指定的命令
type
顯示指定的單詞如果作為命令將會如何被解釋
typeset
聲明一個變量或變量類型。
ulimit
為系統用戶設置指定的資源的上限
umask
為新建的文件和目錄設置默認權限
unalias
刪除指定的別名
unset
刪除指定的環境變量或 shell 屬性
wait
等待指定的進程完成,并返回退出狀態碼
總結
以上是生活随笔 為你收集整理的shell内建命令 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。