2.4 管道和重新導向
2.4.1 重新導向
檔案描述符 重新導向 描述
0 < 標準輸入
1 > 標準輸入
2 > 標準錯誤輸出
>> 追加
2>&1 標準輸出和錯誤輸出到同一個檔案中
特別的,可以用/dev/null來有效丟棄所有的輸出資訊
..... >/dev/null 2>&1
顯示命令 > 檔案
more/less < 檔案
2.4.2 管道:串連進程,使得串連的進程可以同時運行
ps -xo comm|sort|uniq|grep -v sh|more
“|”後面的輸入是其前面的輸出
使得資料流在他們之間可以自動的進行協調。
$ cat mydate.c
dfdfkj
afljir
clkjfoi
而
$cat mydate.c |sort
afljir
clkjfoi
dfdfkj
可見sort不僅可以給目錄呀,檔案呀排序,還可以在在一個檔案內給行排序,但是不能夠在行內排序
而
$ cat mydate.c |sort|>mydate.c
顯示的是空白,原因是你在讀取mydate.c之前就已經覆蓋了這個檔案的內容,因此不能在管道中出現
輸出的檔案是在這一組命令被船艦的同時立刻被建立活寫入。
2.5 shell
shell 指令碼有兩種方式:輸入一系列命令讓shell互動執行,如上;將命令儲存到一個檔案中,將該檔案作為一個程式來調用
萬用字元
* 任一字元串
? 單個字串
[abc...] 匹配方括弧內任意一個單字元
[^abc..] 匹配除了方括弧內任意一個單字元
{ab,dcd,...} 允許任意的字串分組在一個集合中
如 my{ma,fa}se 值得就是 mymase myfase
2.5.1 互動式程式
直接在shell中輸入命令,不過沒法儲存,沒有重用性
2.5.2指令碼
1 建立
# :注釋符
#!/bin/sh :告訴系統後面的參數/bin/sh是用來執行本檔案的程式
exit:確保程式返回一個有意義的退出碼,當從另一個指令碼程式裡調用這個指令碼並查看是否執行成功,退出碼就很重要。
$ file first :用於檢查檔案類型
first: POSIX shell script text executable
2.5.3 執行
a. /bin/sh 指令碼名
b. chmod +x 指令碼名
指令碼名
或者是 ./指令碼名 把指令碼程式的完整的相對路徑且能夠保證不會意外執行系統中於你的指令檔通明的另一個命令。
如果此時告訴你沒有找到該命令,是因為shell的PATH中沒有被設定為目前的目錄下尋找執行的命令。
方法一:在命令列上 PATH=¥PATH:.
方法二:將 指令碼名 添加到 .bash_profile中,退出後重新登入
3.6 SHELL 文法
2.6.1 變數
使用變數前不需要聲明。預設以字串看待和儲存的。
在變數名前加 $ 訪問起內容。但為其賦值時,只需要變數名
1 使用引號
ke=ma ld
ld: no input files
對於有空格的必須用引號
$ke="ma ld"
$ echo $ke
ma ld
$ read ke 等待輸入
dkf klfdj kle 輸入
$ echo $ke
dkf klfdj kle 原文輸出
#!/bin/sh
myvar="Hi there"
echo $myvar // Hi there
echo "$myvar" // Hi there
echo "myvar" // myvar
echo '$myvar' // $myvar
echo 'myvar' // myvar
echo /$myvar // $myvar
echo /myvar // myvar
echo Enter some text // Enter some text
read myvar // 等待輸入
// 輸入 HOW DO YOU DO
echo '$myvar' now equals $myvar // $myvar now equals HOW DO YOU DO
exit 0
從上面的實驗可以知道:
1 對於變數的引用 使用 “”和不使用是一樣的
2 在“”中沒有 $ 的變數 只是字串而已
3 ‘’的作用就是輸出其中的字串
4 / 的作用和 ‘’相同
2 環境變數
$HOME 目前使用者的主目錄
$PATH 以冒號分割的用來搜尋命令的目錄列表
$PS1 命令提示字元
$IFS 輸入欄位分割符,空格、TAB,ENTER
$0 shell指令碼的名字
$# 傳遞給指令碼的參數個數
$$ shell指令碼的進程號
3 參數變數
$1,$2,... 指令碼程式的參數
$* 在一個變數中列出所有的參數,參數間用IFS中的第一個字元分割開
$@ 與 $*意同,不使用IFS
$ IFS=''
$ set foo bar bam
$ echo $@
foo bar bam
$ echo "$@"
foo bar bam
$ echo $*
foo bar bam
$ echo "$*"
foobarbam
$ unset IFS
$ echo $IFS
$ echo "$*"
foo bar bam
如果想訪問指令碼程式的參數,用 $@ 最好
sa="Hello" //
echo $sa //Hello
echo "The program $0 is now running" // biangliang shell指令碼的名字
echo "The second parameter was $2" // bar
echo "The first parameter was $1" // foo
echo "The parameter list was $*" //foo bar baz
echo "The script is now complete"
$ /bin/sh bianliang foo bar baz
2.6.2 條件
shell指令碼對任何從命令列上被調用的命令的退出碼進行測試。
test / [ 布爾判斷命令 且" ["用“]”來結尾
if [ -f /bin/bash ] //注意保持距離
then
echo "file /bin/bash exists"
fi
if [ -d /bin/bash ]
then
echo "/bin/bash is a directory"
else
echo "/bin/bash is NOT a directory"
fi
執行結果為:
$ /bin/sh panduan
file /bin/bash exists
/bin/bash is NOT a directory
2.6.3 控制結構
echo "Please answer yes or no : Is it morning?" //shell用echo -e,bash用echo -n來去除分行符號
read timeofday
if [ $timeofday = "yes" ] //一定要保持距離 if[ $timeofday 不行 ; if [ $timeofday="yes"也不行
then
echo "Good morning"
elif [ $timeofday = "no" ] //[ 對timeofday的內容進行測試,測試結果由if判斷
then
echo "Good afternoon"
else
echo "Sorry,$timeofday is not recognized.Enter yes or no!"
exit 1
fi
exit 0
看似完美的程式,其實隱患重重,在不輸入任何資料,直接ENTER後
[: 15: yes: unexpected operator
[: 15: no: unexpected operator
Sorry, is not recognized.Enter yes or no!
問題出在 當直接ENTER後,$timeofday 成為 Null 字元串
因此將 $timeofday 改為"$timeofday"
4 for 語句
for 迴圈經常與shell的檔案名稱擴充一起使用
for variable in values_table
do
...$variable
done
for 迴圈經常與shell的檔案名稱擴充一起使用
for file in *.sh
還有就是
for foo in 10
echo "here wo go"
這樣能執行一次
for foo in 1 2 3 4 5 6 7 8 9 10
echo "here wo go"
卻可以執行10次
而
for foo in 1 2 3 5 8 9 41 10 1 0
echo "here wo go"
依然是執行10次
參考:Linux 程式設計(v3)