2021-05-12 14:32:11
Linux基礎知識之IO重定向及管道詳解(關於tr、tee命令)
我在剛開始接觸IO重定向時,經歷了由懂到不懂然後了然的過程,當然現在的我也不可能說對於IO重定向就徹底懂了,只是在解決一些問題或實現某些結果時不會因為IO重定向的問題而迷惑了。
什麼叫IO重定向?
為了解釋這個問題,我們要先明白什麼叫IO,什麼叫做程式的資料流。
什麼叫IO?
在Linux或計算機領域IO指的是資訊的輸入和輸出。
在Linux中可用於輸入的裝置:檔案(Linux中一切皆檔案)
具體包括:鍵盤裝置、檔案系統上的常規檔案、網絡卡等。
在Linux中用於輸出的裝置:檔案
具體包括:顯示器、檔案系統上的常規檔案、網絡卡等。
什麼叫做資料流?
我們通常描述的資訊本質上來說都是資料,因為資訊處於動態,我們就將資訊或者命令等概念稱作流動的資料也就是資料流。
資料流分為輸入流(InputStream)和輸出流(OutputStream)兩類。輸入流只能讀不能寫,而輸出流只能寫不能讀。通常程式中使用輸入流讀出資料,輸出流寫入資料,就好像資料流入到程式並從程式中流出。採用資料流使程式的輸入輸出操作獨立與相關裝置。輸入流可從鍵盤或檔案中獲得資料,輸出流可向顯示器、印表機或檔案中傳輸資料。
在Linux中,程式的資料流有三種:
輸入的資料流:←標準輸入 STDIN 常用裝置:鍵盤
輸出的資料流:→標準輸出 STDOUT 常用裝置:終端
錯誤輸出流: →錯誤輸出 STDERR 常用裝置:終端
在Linux中開啟一個檔案,在該檔案被載入完成後對於系統來說需要用一個數位表示,這個數位叫做fd:file descriptor 檔案描述符。
因為Linux系統中一切皆檔案,所以對應的標準輸入裝置,標準輸出裝置,錯誤輸出裝置都有其對應的fd
標準輸入:0
標準輸出:1
錯誤輸出:2
IO重定向的意思就是將系統原本預設的輸入輸出的路徑重新定向到其他檔案。
我知道解釋到這裡還是會很困惑,別著急,這個概念需要通過一定量的實驗來說明。
--------------------------------------------------------------------------------
輸出重定向
其常用 >、 >> 、>|這三種表示
>:覆蓋輸出 >>:追加輸出 >|:強行覆蓋
因為使用>不當會對原有的資料造成很大的影響,所以有時候我們會手動設定關閉>的特性。其命令為:
set -C禁止覆蓋輸出重定功能
set +C為開啟覆蓋輸出重定向功能
不過上述命令對“>|”無效
下面以具體實驗來說明上面內容
實驗環境:在/test/目錄下
[root@localhost test]# ll
總用量 0
[root@localhost test]# echo $(date) > t1
[root@localhost test]# ll
總用量 4
-rw-r--r--. 1 root root 43 8月 2 18:15 t1
[root@localhost test]# cat t1
2016年 08月 02日 星期二 18:15:28 CST
[root@localhost test]# echo test > t1
[root@localhost test]# cat t1
test
[root@localhost test]# echo $(who) >> t1
[root@localhost test]# cat t1
test
root :0 2016-08-02 10:12 (:0) root pts/0 2016-08-02 10:12 (192.168.85.1) root pts/1 2016-08-02 10:19 (192.168.85.1)
[root@localhost test]# set -C
[root@localhost test]# echo 111 > t1
-bash: t1: 無法覆蓋已存在的檔案
[root@localhost test]# echo 111 >| t1
[root@localhost test]# cat t1
111
上面的結果顯示了>、>>、>|三者的各自功能
相信看到這裡對於輸入重定向會有了進一步的認識。
--------------------------------------------------------------------------------
錯誤輸出流重定向
2>
[root@localhost test]# echoo 1 > t2
bash: echoo: 未找到命令...
當命令錯誤時,shell會返回錯誤資訊,若我們想將錯誤資訊存到某個檔案則可按如下操作
[root@localhost test]# echoo 1 2> t2
-bash: t2: 無法覆蓋已存在的檔案
[root@localhost test]# ll
總用量 4
-rw-r--r--. 1 root root 4 8月 2 18:18 t1
-rw-r--r--. 1 root root 0 8月 2 18:20 t2
[root@localhost test]# echoo 1 2> t3
[root@localhost test]# cat t3
bash: echoo: 未找到命令...
[root@localhost test]# echop wqew 2>>t3
[root@localhost test]# cat t3
bash: echoo: 未找到命令...
相似命令是: 'echo'
bash: echop: 未找到命令...
錯誤重定向也支援追加。
如果我們不管命令對錯都想記錄那麼可以使用如下格式實現:
1、&>、 &>>
[root@localhost test]# ech2 &>> t4
[root@localhost test]# echo right &>> t4
[root@localhost test]# cat t4
bash: ech2: 未找到命令...
right
2、command >> /path/somewhere ... 2>&1 第二種只能為此種格式,不管前面是追加還是覆蓋後面均為2>&1。2>>&1為錯誤格式,使用後在CentOS7.2下會報錯。
[root@localhost test]# ech2 >> t5 2>&1
[root@localhost test]# echo right >> t5 2>&1
[root@localhost test]# cat t5
bash: ech2: 未找到命令...
right
註:輸出重定向的物件可以是各種檔案,但不能將其定向至命令的輸入,要想實現這個功能則需要用管道。這裡大家可能有點迷,下面以例子說明
[root@localhost test]# who > tr a-z A-Z > t6
[root@localhost test]# cat t6
root pts/0 2016-08-02 10:12 (192.168.85.1)
[root@localhost test]# ll
總用量 4
-rw-r--r--. 1 root root 54 8月 2 18:53 t6
-rw-r--r--. 1 root root 0 8月 2 18:53 tr
我們將who顯示的命令重定向至tr命令的輸入,之後將內容小寫轉換為大寫後再重定向至t6檔案。我們想實現的是這個結果,但是並沒有實現,反而在過程中出現了tr這個檔案。這是因為在第一層的重定向中,預設將tr當做檔名,但是奇怪的是tr內什麼都沒有,所以這種錯誤的理解盡早擺脫。
[root@localhost test]# cat tr
[root@localhost test]#
我們可以使用管道完美解決上面的問題。
[root@localhost test]# who | tr a-z A-Z > t6
[root@localhost test]# cat t6
ROOT :0 2016-08-02 10:12 (:0)
ROOT PTS/0 2016-08-02 10:12 (192.168.85.1)
ROOT PTS/1 2016-08-02 10:19 (192.168.85.1)
什麼是管道,我相信通過上面的例子大家應該對它有了個初步的認知。
管道:連線程式,實現將前一個命令的輸出直接定向後一個程式當做輸入資料流。
其常用表達格式如下: COMMAND1 | COMMAND2 | COMMAND3 |...
它是輸出重定向的補充與加強,其本質還是類屬於輸出重定向。
既然說道管道,這裡再多補充點
常用於管道的命令:
tee
tee - read from standard input and write to standard output and files
顯示標準輸入的結果並將其寫入檔案
tee的使用格式:
命令1 | tee 檔名| 命令2
把命令1的STDOUT儲存在檔名中,然後管道輸入給命令2
作用:
儲存不同階段的輸出
複雜管道的故障排除
同時檢視和記錄輸出
下面通過一個簡單的例子說明tee的具體作用
[root@localhost test]# who | tee t2 | tr a-z A-Z
ROOT :0 2016-08-02 10:12 (:0)
ROOT PTS/0 2016-08-02 10:12 (192.168.85.1)
ROOT PTS/1 2016-08-02 10:19 (192.168.85.1)
[root@localhost test]# cat t2
root :0 2016-08-02 10:12 (:0)
root pts/0 2016-08-02 10:12 (192.168.85.1)
root pts/1 2016-08-02 10:19 (192.168.85.1)
tee可以將前一個的結果記錄在t2檔案內,同時顯示後一個命令的結果。
--------------------------------------------------------------------------------
輸入重定向
< 單行模式、 << 多行模式
要了解輸入重定向,我們得先了解一個命令
tr
tr - translate or delete characters 轉換或刪除字元
其表達格式如下:
tr[OPTION]... SET1 [SET2]
選項:
-c或——complerment:取字元集的補集
-d或——delete:刪除所有屬於第一字元集的字元
-s或—squeeze-repeats:把連續重複的字元以單獨一個字元表示
下面我們通過一個例子簡要了解下tr的作用
12345678 [root@localhost test]# cat t1
root :0 2016-08-02 10:12 (:0)
root pts/0 2016-08-02 10:12 (192.168.85.1)
root pts/1 2016-08-02 10:19 (192.168.85.1)
[root@localhost test]# tr a-z A-Z < t1
ROOT :0 2016-08-02 10:12 (:0)
ROOT PTS/0 2016-08-02 10:12 (192.168.85.1)
ROOT PTS/1 2016-08-02 10:19 (192.168.85.1)
t1是上面tee儲存的who內容,我們通過輸入重定向將其作為tr的輸入,並由小寫轉換為大寫。
輸入重定向就是將原來用鍵盤輸入的內容通過其他文字內容或檔案內容代替。
我想大家對於<<多行重定向有些不理解,這裡再對多行重定向在以例子說明一下。
12345678 [root@localhost ~]# tr a-z A-Z << end
> morning,boys
> today is another day
> please be happy
> end
MORNING,BOYS
TODAY IS ANOTHER DAY
PLEASE BE HAPPY
多行輸入重定向後面需要接規定的結尾字串,通常使用eof或end為結尾標示符。
多行輸入重定向需要手動鍵入內容。單行輸入重定向則需要跟檔案或前一個命令的輸出結果。
--------------------------------------------------------------------------------
我知道看到這裡依然會有點懵,下面通過9個範例來綜合使用標準輸出輸???及管道命令。
實驗環境CentOS7.2
1、將/etc/issue檔案中的內容轉換為大寫後儲存至/test/issue#檔案中
1234567 [root@localhost test]# cat /etc/issue | tr a-z A-Z > /test/issue1
[root@localhost test]# echo $(tr a-z A-Z < /etc/issue) > /test/issue2
[root@localhost test]# cat issue1
S
KERNEL R ON AN M
[root@localhost test]# cat issue2
S KERNEL R ON AN M
上面兩種方式均可以實現要求,只不過輸出格式略有不同,這根命令有關。在沒有進一步的限制下,這兩種表達方式均可。第一種使用管道,輸出重定向,第二種使用命令參照,輸入重定向及輸出重定向。
2、將當前系統登入使用者的資訊轉換為大寫後儲存至/test/t2檔案中
12345 [root@localhost test]# who | tr a-z A-Z > /test/t2
[root@localhost test]# cat t2
ROOT :0 2016-08-02 10:12 (:0)
ROOT PTS/0 2016-08-02 10:12 (192.168.85.1)
ROOT PTS/1 2016-08-02 10:19 (192.168.85.1)
3、一個linux使用者給root發郵件,要求郵件標題為”help”,郵件正文如下:
Hello, I am 使用者名稱,the system version is here,pleasehelp me to check it ,thanks!
作業系統版本資訊
我們使用使用者gentoo
[root@localhost ~]# su gentoo
[gentoo@localhost /root]$ whoami
gentoo
[gentoo@localhost /root]$ cd /home/gentoo/
[gentoo@localhost gentoo]$ echo -e "Hello,I am `whoami`nThe system version is here,please help me to check it ,thanks.nThe version is `cat /etc/RedHat-release`" | mail -s "help" root
[gentoo@localhost gentoo]$ exit
exit
您在 /var/spool/mail/root 中有新郵件
[root@localhost ~]# mail
Heirloom Mail version 12.5 7/5/10. Type ? for help.
"/var/spool/mail/root": 3 messages 1 new
1 gentoo@localhost.loc Tue Aug 2 09:38 21/731 "help"
2 root Tue Aug 2 09:44 21/741 "help"
>N 3 gentoo@localhost.loc Tue Aug 2 19:37 20/737 "help"
& 3
Message 3:
From gentoo@localhost.localdomain Tue Aug 2 19:37:36 2016
Return-Path: <gentoo@localhost.localdomain>
X-Original-To: root
Delivered-To: root@localhost.localdomain
Date: Tue, 02 Aug 2016 19:37:36 +0800
To: root@localhost.localdomain
Subject: help
User-Agent: Heirloom mailx 12.5 7/5/10
Content-Type: text/plain; charset=us-ascii
From: gentoo@localhost.localdomain
Status: R
-e Hello,I am gentoo
The system version is here,please help me to check it ,thanks.
The version is CentOS Linux release 7.2.1511 (Core)
這裡使用了命令替換來顯示使用者及版本資訊,管道將第一個命令的輸出遞給下一個命令作為其輸入。
4、將/root/下檔案列表,顯示成一行,並檔名之間用空格隔開
[root@localhost test]# ls -1 /root | tr 'n' ' 'n
anaconda-ks.cfg CST dead.letter file initial-setup-ks.cfg test.txt tr 公共 模板 視訊 圖片 文件 下載 音樂 桌面 [root@localhost test]#
上面命令已經滿足我們的要求了,只不過不換行看著有些彆扭,下面我們在完善下使其輸出看著更舒服些。
[root@localhost test]# echo -e `ls -1 /root/ | tr 'n' ' 'n`
anaconda-ks.cfg CST dead.letter file initial-setup-ks.cfg test.txt tr 公共 模板 視訊 圖片 文件 下載 音樂 桌面
[root@localhost test]#
使用echo的-e開啟跳脫符使換行n生效。
5、file1檔案的內容為:”1 2 3 4 5 6 7 8 9 10” 計算出所有數位的總和
[root@localhost test]# cat > file1
1 2 3 4 5 6 7 8 9 10
^C
[root@localhost test]# cat file1
1 2 3 4 5 6 7 8 9 10
先建立file1資料夾並輸入題目要求內容。
12 [root@localhost test]# cat file1 | tr ' ' '+' | bc
55
6、處理字串“xt.,l 1 jr#!$mn2 c*/fe3 uz4”,只保留其中的數位和空格
[root@localhost test]# echo 'xt.,l 1 jr#!$mn2 c*/fe3 uz4' | tr -cd '[:digit:][:space:]'
1 2 3 4
這裡使用了tr中的-c及-d補集跟刪除,靈活使用補集概念可以更準確的幫助我們過濾不需要的資訊。
7、將PATH變數每個目錄顯示在獨立的一行
[root@localhost test]# echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost test]# echo ${PATH} | tr ':' 'n'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin
這個題很簡單只需要將PATH正確顯示出來,使用tr將:替換為換行即可
8、刪除指定檔案的空行
這裡我們建立一個含有很多空行的文字檔案t9
[root@localhost test]# cat t9
q
ere
s
df
sd
sd
[root@localhost test]# cat t9 | tr -s 'n'
q
ere
s
df
sd
sd
這裡使用了tr的重復刪除-s選項。
9、將檔案中每個單詞(字母)顯示在獨立的一行,並無空行
這裡我們選擇/etc/rc.d/rc0.d/K50netconsole檔案,使用head檢視下其檔案前5行都什麼內容
[root@localhost test]# head -5 /etc/rc.d/rc0.d/K50netconsole
#!/bin/bash
#
# netconsole This loads the netconsole module with the configured parameters.
#
# chkconfig: - 50 50
[root@localhost test]# cat /etc/rc.d/rc0.d/K50netconsole | tr -cs '[:alpha:]' 'n' | head -5
bin
bash
netconsole
This
從結果來看我們實現了題目的要求,不過為什麼第一行是空行,這是因為-s是將所有的空行壓縮為一行,因此前面會留有一行空行。
本文永久更新連結地址:http://www.linuxidc.com/Linux/2016-08/134037.htm
相關文章