Linux 的輸入與輸出及pipeline
標準的輸入、輸出與管線
標準的資料通道
- Linux有三個標準的資料通道,分別是:
- stdin 編號 0 --預設為鍵盤
- stdout 編號 1 --預設為windows終端機
- stderr 編號 2 --預設為windows終端機
- 簡單的說明
[mtchang@server1 ~]$ ls -l Desktop fakefile # STDERR 輸出 ls: fakefile: No such file or directory # STDOUT 輸出 Desktop: total 12 -rw-r--r-- 1 mtchang mtchang 4803 Jan 7 2007 gnome-terminal.desktop -rw-rw-r-- 1 mtchang mtchang 260 Aug 14 19:54 Thunderbird.desktop
轉移輸出
- Linux的轉移資料字元:
- < 轉向標準輸入
- > 轉向輸出,如果該目標(檔案)已存在會覆蓋。
- 1> stdout轉向輸出,如果該目標(檔案)已存在會覆蓋。
- >> 轉向輸出如果該目標(檔案)已存在會添加在檔案後面。
- 1>> stdout轉向輸出如果該目標(檔案)已存在會添加在檔案後面。
- 2> stderr轉向輸出,如果該目標(檔案)已存在會覆蓋。如不想覆蓋可使用2>>添加在檔案後面。
- 2>> stderr轉向輸出,如果該目標(檔案)已存在會添加在檔案後面。
- &> all(0,1,2)轉向輸出到目標(檔案)
- &1> stdout的輸出轉向到目標(檔案)
- &2> stderr的輸出轉向到目標(檔案)
- &1 代表stdout的輸出
- &2 代表stderr的輸出
- Linux的特殊裝置 /dev/null 黑洞,任何輸入到/dev/null的資料皆會消失不顯示於任何地方。
- < 轉向標準輸入的範例,把ls的內容轉入給mail程式
[lcc09@localhost ~]$ ls > ls [lcc09@localhost ~]$ cat ls Desktop ls public_html [lcc09@localhost ~]$ mail lcc09 < ls [lcc09@localhost ~]$ mail Mail version 8.1 6/6/93. Type ? for help. "/var/spool/mail/lcc09": 1 message 1 new >N 1 lcc09@localhost.loca Fri May 25 20:50 17/659 & 1 Message 1: From lcc09@localhost.localdomain Fri May 25 20:50:09 2007 Date: Fri, 25 May 2007 20:50:09 +0800 From: lcc09To: lcc09@localhost.localdomain Desktop ls public_html & q Saved 1 message in mbox
- 一個帶有 stdout 及 stderr 輸出的指令
[lcc09@localhost ~]$ ls ~/ /rec ls: /rec: 沒有此一檔案或目錄 /home/lcc09/: Desktop public_html
- 將 stderr 轉到 /dev/null 所以看不到錯誤的訊息
[lcc09@localhost ~]$ ls ~/ /rec 2> /dev/null /home/lcc09/: Desktop public_html
- 將 stderr 接到 stdout ,並將 stdout 存到 list
- >list :stdout轉向輸出到 list 檔案
- 2>&1 :stderr轉向輸出到 &1(stdout)
- &參考的檔案描述,為標準輸出編號,&1代表stdout
[lcc09@localhost ~]$ ls ~/ /rec > list 2>&1 [lcc09@localhost ~]$ more list ls: /rec: 沒有此一檔案或目錄 /home/lcc09/: Desktop list mbox public_html
- 使用echo以keyboard為輸入裝置,並在銀幕上輸入文字,最後轉存到檔案。
[lcc09@localhost ~]$ echo "hello tux > > how r u > i okey?? > save " > greetings
- 練習:寫一個 shell script 可以自動產生一個 index.html 檔案,內容為標準的 html 檔案結構,並且在 body 內放入今天的日期。
[student@server1 ~]$ ./html.sh [student@server1 ~]$ nano html.sh #!/bin/bash echo " $(date +%Y%m%d) " > index.html [student@server1 ~]$ ./html.sh [student@server1 ~]$ cat index.html 20091209
補充:mail 指令的使用
- mail:送出和接收email
- 在命令列輸入 mail 即可進入 mail 程式內收發信件
- 若想寫信給他人,則在命令列輸入 mail 收信者帳號 ,即可發送信件給「收信者」
- 若想將既有的文字檔當成信件內容寄給他人,則在命令列輸入
mail 收信者帳號 -s 信件主題 < 文件檔名稱
即可將「文件檔名稱」發送給「收信者」
- 在 mail 程式中
- 輸入 ? 查詢所有指令
- 輸入 h 列出所有信件
- 輸入 t 閱讀信件
- 輸入 n 閱讀下一封信件
- 輸入 d 刪除信件
- 輸入 u 救回刪除信件
- 輸入 R 回覆信件
- 輸入 m 收信者帳號 發送信件給「收信者」
- 輸入 q 離開 mail 程式,並將閱讀過的所有信件存至「mbox」檔案
- 輸入 x 離開 mail 程式
- 寄信
[mtchang@mt test]$ mail mtchang Subject: test test . Cc:
- 看信
[mtchang@mt test]$ mail Mail version 8.1 6/6/93. Type ? for help. "/var/spool/mail/mtchang": 1 message 1 new >N 1 mtchang@localhost.lo Tue Oct 14 17:11 16/644 "test" & 1 Message 1: From mtchang@localhost.localdomain Tue Oct 14 17:11:35 2008 Date: Tue, 14 Oct 2008 17:11:35 +0800 From: mtchangTo: mtchang@localhost.localdomain Subject: test test & q Saved 1 message in mbox
標準輸出到程式(Piping)
- 管線指令 pipe(|)
[lcc09@localhost ~]$ command1 | command2 # 將command1的輸出導入到command2的輸入
- less 把輸出限制在一個頁面上,並且可以做功能性的操作,將ls輸出導入到less的輸入。
ls -l /etc | less
- mail 寄郵件,將內容為「test email」的內容以「test」的主旨寄給 student@localhost 使用者,此功能可以寄出到外界的信箱,但是大部分的主機都會將其列為垃圾信件。
echo "test email" | mail -s "test" student@localhost
- lpr 列印,或指定列印到某台印表機
echo "test print" | lpr echo "test print" | lpr -p printer_name
- 把 man ls 的資訊交由 col -b 過濾控制碼,並將其轉輸出到 ls.txt 檔案
[root@server1 ~]# man ls | col -b > ls.txt
多目標轉移
- tee 指令的搭配,tee指令是一個雙向指令,會將標準輸入輸出到兩個地方(檔案及標準輸出)
- $ command1 | tee filename
- 常見用途:
- pipelines 命令除錯
- 想要看結果也想要作logging
- 簡單範例
[lcc09@localhost ~]$ man tee | col -b > tee.txt # 將man tee的結果導入到col -b的輸入,並將結果輸出到tee.txt [lcc09@localhost ~]$ ls -l | tee output # tee這個指令是一個雙向指令,會將標準輸入輸出到兩個地方(檔案及標準輸出)
- 將man tee的結果導入到col -b的輸入,將col -b 的結果輸出tee程式,由tee分配到ls.txt檔案及STDOUT(螢幕)
[lcc09@localhost ~]$ man ls | col -b | tee ls.txt
tr 轉換字元
- tr 轉換字元
[lcc09@localhost ~]$ tr 'a-z' 'A-Z' < .bash_history # 將 .bash_history的英文字母a-z轉換成大寫的A-Z [lcc09@localhost ~]$ cat .bash_history | tr 'a-z' 'A-Z' # 這命令和上述的命令結果一樣
送出多行文字到STDIN
- STDIN可以在命令列中使用 <
- All text until WORD is sent to STDIN
- Sometimes called a heretext
[lcc09@localhost ~]$ mail -s 'please call' root << END > hello root > good by > END [lcc09@localhost ~]$
- ctrl+D 結束輸入
Scripting:for loop array
- 迴圈的語法與應用
for 的語法文字串方式
- for 的語法文字串方式
for 變數 in 數值1 數值2 數值3
do
# 迴圈內容,$變數可以取用迴圈帶入的數值
echo $變數
done
簡單的測試 for 迴圈示範
- 程式碼,檔案 for.sh,請建立如下程式
[student@server1 ~]$ nano for.sh
#!/bin/bash
for NAME in root student mtchang
do
echo $NAME
done
- 賦予可執行權
[student@server1 ~]$ chmod +x for.sh
- 執行結果,變數把root student mtchang三個文字依序帶入迴圈並顯示
[student@server1 ~]$ ./for.sh root student mtchang
迴圈中使用Name的方式
- 此範例為寄信給root、mtchang及student的使用者
[student@server1 ~]$ vi loop.sh
#!/bin/bash
# for 迴圈開始,第1次載入 root ,第2次載入 mtchang,第3次載入 student
# 底下程式碼請注意空白、單引號及雙引號的不同
for NAME in root mtchang student
do
# 將收件人$NAME存為變數ADDRESS
ADDRESS="$NAME"
# 將信件內容寫成變數MESSAGE
MESSAGE='Projects are due today!'
# mail 指令簡單用法
# echo '內容' | mail -s '標題' 收件人
echo $MESSAGE | mail -s Reminder $ADDRESS
done
for 的語法:數值方式
- for 的語法:數值方式
for 變數 in {整數值..整數值}
do
# 迴圈內容,$變數可以取用迴圈帶入的數值
echo $變數
done
產生一各簡單的for迴圈
- for 迴圈:產生 1 至 20的整數
[lcc09@localhost ~]$ vi num.sh
#!/bin/bash
for n in {1..20}; do
echo $n
done
檢測目前網段的機器,簡單寫法
- 「$?」變數代表前一各指令正確執行成功。
- $?=1 則前一各指令執行失敗
- $?=0 則前一各指令執行成功
for n in {1..5};
do
h="192.168.3.$n"
echo $h
# 讓 stdout 不輸出,畫面會比較乾淨
# ping -c1 $h > /dev/null
echo "return value = $? "
done
檢測目前網段的機器
- 檢測目前網段的機器,存活的機器。
- 「$?」變數代表前一各指令正確執行成功。
- $?=1 則前一各指令執行失敗
- $?=0 則前一各指令執行成功
#!/bin/bash
# alive2.sh
for n in {1..20}; do
host=192.168.1.$n
ping -c1 $host &> /dev/null
if [ $? = 0 ]; then
echo "$host id UP"
else
echo "$host id DOWN"
fi
done
變數值使用命令帶入
- 在變數的部份,使用命令或是檔案帶入的情形
- 先測是底下的指令,從 /etc/passwd 檔案找出帶有 bash 的行
[root@localhost ~]# grep bash /etc/passwd root:x:0:0:root:/root:/bin/bash lcc09:x:500:500:lcc09:/home/lcc09:/bin/bash student:x:501:501::/home/student:/bin/bash
- 寫個script將此指令結果帶入迴圈
[root@localhost ~]# vim foruser.sh #!/bin/bash for USER in $(grep bash /etc/passwd) do echo $USER done # 賦予可執行權限 [root@localhost ~]# chmod +x foruser.sh # 執行 [root@localhost ~]# ./foruser.sh root:x:0:0:root:/root:/bin/bash lcc09:x:500:500:lcc09:/home/lcc09:/bin/bash student:x:501:501::/home/student:/bin/bash
變數值使用文字檔案帶入
- 使用指令 cat 觀看一個文字檔案
[root@localhost ~]# cat /etc/issue Welcome ! Red Hat Enterprise Linux Server release 5.1 (Tikanga) Kernel \r on an \m
- 程式 forfile.sh
#!/bin/bash for FILE in $(cat /etc/issue) do echo $FILE done
- 執行結果
[root@localhost ~]# ./forfile.sh Welcome ! Red Hat Enterprise Linux Server release 5.1 (Tikanga) Kernel \r on an \m
Scripting:array
- bash下array的幾種使用方法
#!/bin/bash
#一舉將變數設定到陣列中
array=(Redhat Novell MicroSoft Sun IBM HP Dell)
#利用for loop將陣列中的變數印出
for i in 0 1 2 3 4 5 6
do
echo "array[$i]=${array[$i]}"
done
#設定間隔符號為: 搭配$*將陣列的值一口氣輸出
IFS=:
echo "${array[*]}"
#設定間隔符號為換行,搭配$*將陣列的值一口氣輸出
IFS=$'\n'
echo "${array[*]}"
#將陣列中的值利用$@一口氣輸出與$*不同的是,不會將值合併成單一字串
echo "${array[@]}"
#印出陣列中有幾筆資料
echo "${#array[@]}"
執行結果:
array[0]=Redhat
array[1]=Novell
array[2]=MicroSoft
array[3]=Sun
array[4]=IBM
array[5]=HP
array[6]=Dell
Redhat:Novell:MicroSoft:Sun:IBM:HP:Dell
Redhat
Novell
MicroSoft
Sun
IBM
HP
Dell
Redhat Novell MicroSoft Sun IBM HP Dell
7
留言