組命令和子shell
在bash中,有兩種方式可以將命令組合到一起,一種是組命令,另一種是子shell。格式如下:
# 組命令
{ commnad1; command2; [ command3.. ] }
# 子shell
(command1; command2; [command3..])
上面兩種形式的差別在于:1.組命令使用花括號括起來,前花括號和后花括號與命令之間要有一個空格,并且閉合花括號前要用分號或換行結(jié)束命令。2.對于子shell,只需要用圓括號包圍即可。
執(zhí)行重定向
那么,組命令和子shell有什么用途呢?盡管它們有一個主要的區(qū)別,但是它們都可以用來管理重定向。下面請看這個例子:
[fbap:/home/fbap/usertmp]>ls -l > output.txt
[fbap:/home/fbap/usertmp]>echo "hello world" >> output.txt
[fbap:/home/fbap/usertmp]>cat foo.txt >> output.txt
顯然,上面的3條命令將輸出重定向到output.txt。使用組命令,可以將它們合并成一行:
{ ls -l; echo "hello world"; cat foo.txt; } > output.txt
當(dāng)然,你也可以使用子shell的方式:
(ls -l; echo "hello world"; cat foo.txt;) > output.txt
在上面的例子中,使用組命令和子shell可以減少一些輸入。但是,組命令和子shell真正有價值的地方在于管道的使用。當(dāng)創(chuàng)建命令管道時,通常將多條命令的結(jié)果輸出到一條流中,這很有用。
{ ls -l; echo "hello world"; cat foo.txt; } | lpr
這里,我們將3個命令的輸出進(jìn)行合并,并通過管道輸出到lpr的輸入以產(chǎn)生一個打印報告。
進(jìn)程替換
雖然組命令和子shell看起來很相似,都可以用來為重定向整合流,但是,它們有一處主要的不同。子shell(正如其名字)在當(dāng)前shell的子拷貝中執(zhí)行命令,而組命令則是直接在當(dāng)前shell中執(zhí)行所有命令。這以為子shell會復(fù)制當(dāng)前環(huán)境變量以創(chuàng)建一個新的shell實例。當(dāng)子shell退出時,復(fù)制的環(huán)境變量也就消失了,因此對任何子shell(包括變量賦值)的改變也同樣丟失了。所以,大多數(shù)情況下,除非腳本需要子shell,否則使用組命令比子shell更快,占用內(nèi)存也更少。
請看下面的例子:
echo 'foo' | read
echo $REPLY
在上面的例子中,REPLY的內(nèi)容總是空的,因為read命令是在子shell中執(zhí)行的,并且當(dāng)子shell終止的時候,REPLY的拷貝也遭到了破壞。
很幸運的是,shell提供了一種叫做進(jìn)程替換的外部擴展方式來解決這個問題。
實現(xiàn)進(jìn)程替換的方式有兩種:
# 產(chǎn)生標(biāo)準(zhǔn)輸出的進(jìn)程
<(list)
# 吸納標(biāo)準(zhǔn)輸入的命令
>(list)
為了解決上述read命令的問題,我們可以像這樣使用進(jìn)程替換:
read < <(echo "foo")
echo $REPLY
進(jìn)程替換允許將子shell當(dāng)成普通的文件,目的是為了重定向。事實上,這是一種擴展形式,我們可以查看它的真實值。
[fbap:/home/fbap]>echo <(echo "foo")
/dev/fd/63
通過使用echo查看擴展結(jié)果,可以看到文件/dev/fd/63正為子shell提供輸出。
以下是一個讀循環(huán)的實例,該實例用循環(huán)處理子shell創(chuàng)建的目錄列表的內(nèi)容:
#!/bin/bash
# 注:
# 1.如果將此處的內(nèi)容另存為一個腳本如sub-proc.sh,但是如果像這樣執(zhí)行腳本:sh sub-proc.sh,shell將報錯syntax error(語法錯誤)。
#
# 正確的執(zhí)行方式是:
# 1)腳本添加可執(zhí)行權(quán)限: chmod u+x sub-proc.sh
# 2)使用相對(絕對)路徑: ./sub-proc.sh
while read attr links owner group size date_1 date_2 year filename
do
cat <<EOF
文件名: ${filename}
大小: ${size}
擁有者: ${owner}
屬性: ${attr}
EOF
echo "======================="
done < <(ls -l | tail -n +2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
執(zhí)行命令:./sub-proc.sh | head -n 10,得到如下輸出:
[fbap:/home/fbap/usertmp]>./sub*sh|head -n 10
文件名: AFA_TEST_NEWADM.ixf
大小: 4783
擁有者: fbap
屬性: -rw-rw-r--.
=======================
文件名: all_python_files.log
大小: 1168088
擁有者: fbap
屬性: -rw-rw-r--.
=======================