Linux 中的數據流重定向

什麼是數據流重定向

在 bash 中,執行命令的數據輸入輸出情況爲:

通常情況下,輸出結果都會輸出到屏幕上,但是如果想要保存輸出結果就需要使用數據流重定向。數據流重定向可以幫助對輸出的結果進行重新定位,使之到達特定的位置。上圖中箭頭上方還有 standard input,standard output,standard error output 等標識,這三者分別代表不同的含義。

standard output,standard error output

因爲都是輸出,因此這兩者可以放在一塊做個對比。

standard output 表示命令正確執行所返回的正確信息,standard error output 表示命令執行失敗後返回的錯誤信息。

上圖中說到,數據流重定向能夠將 standard output 和 standard error output 分別傳送到 screen/file/device 中,其中所涉及到的特殊字符爲:

  • standard input:代碼爲 0,使用 0</< 或 0<</<<。
  • standard output:代碼爲 1,使用 1>/> 或 1>>/>>。
  • standard error output:代碼爲 2,使用 2> 或 2>>。

比如要將當前目錄內的文件信息轉存到文件 fileinfo 中:

[email protected]:/tmp/test$ ll
total 8
drwxrwxr-x  2 wood wood 4096 Apr  4 22:49 ./
drwxrwxrwt 15 root root 4096 Apr  4 22:49 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
[email protected]:/tmp/test$ ll > ./fileinfo
[email protected]:/tmp/test$ ll
total 12
drwxrwxr-x  2 wood wood 4096 Apr  4 22:50 ./
drwxrwxrwt 15 root root 4096 Apr  4 22:49 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood  342 Apr  4 22:50 fileinfo
[email protected]:/tmp/test$ cat fileinfo 
total 8
drwxrwxr-x  2 wood wood 4096 Apr  4 22:50 ./
drwxrwxrwt 15 root root 4096 Apr  4 22:49 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood    0 Apr  4 22:50 fileinfo

通過上邊的結果,我們可以看出:

  • 數據流重定向後不會輸出結果到屏幕
  • 定向文件不存在則自動建立
  • 文件存在則會先將文件內容清空,再寫入

如果需要將數據進行累加,則需要使用 >> 符號:

[email protected]:/tmp/test$ ll >> ./fileinfo 
[email protected]:/tmp/test$ cat fileinfo
total 8
drwxrwxr-x  2 wood wood 4096 Apr  4 22:50 ./
drwxrwxrwt 15 root root 4096 Apr  4 22:49 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood    0 Apr  4 22:50 fileinfo
total 12
drwxrwxr-x  2 wood wood 4096 Apr  4 22:50 ./
drwxrwxrwt 15 root root 4096 Apr  4 22:54 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood  342 Apr  4 22:50 fileinfo

standard error output 的數據流重定向方法與 standard output 相似,只是對應的符號不同。如果需要同時重定向 standard output 和 standard error output 的話,就需要使用:

command > dir1 2> dir2

上邊的命令是將正確信息和錯誤信息分別定向到不同位置,如果兩者的位置一樣,爲了防止出現存儲順序錯誤,就需要使用特殊的寫法:

command > dir 2>&1
command &> dir

上邊的兩種寫法都是可行的。

/dev/null

從上圖中我們知道,數據流可以定向到設備中,在 Linux 中存在一個很特殊的設備,該設備就是 /dev/null。該設備會吸收一切定向到該設備的信息:

[email protected]:/tmp/test$ ll > /dev/null 
[email protected]:/tmp/test$ cat /dev/null 

雖然直接使用 cat 命令查看一個設備這樣的命令看起來很奇怪,但是結果卻是和我們想象的完全一樣。

standard input

standard input 可以對比 standard output 來看,是將輸入定向到某一個位置,也就是數據的來源問題。

其實大多數命令除了命令名外,還需要我們手動地輸入某些選項或者參數,對於這些選項和參數,也就可以從輸入設備導入:

[email protected]:/tmp/test$ cat > cmdarg
[email protected]:/tmp/test$ cat >> fileinfo < ./cmdarg 
[email protected]:/tmp/test$ cat fileinfo 
total 8
drwxrwxr-x  2 wood wood 4096 Apr  4 22:50 ./
drwxrwxrwt 15 root root 4096 Apr  4 22:49 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood    0 Apr  4 22:50 fileinfo
total 12
drwxrwxr-x  2 wood wood 4096 Apr  4 22:50 ./
drwxrwxrwt 15 root root 4096 Apr  4 22:54 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood  342 Apr  4 22:50 fileinfo
fileinfo

在上邊的程序中,我們首先輸入文件內容到 cmdarg,然後再將文件內容添加到 fileinfo 中,輸出的結果和我們考慮的也是一致的。

由於沒有輸入換行,格式可能會有點不太整齊。

我們之前提到過 >> 和 2> 分別表示追加定向,而 << 的含義就不太一樣了,<< 表示結束的輸入字符,比如:

[email protected]:/tmp/test$ cat > filee << "xxx"
> filea
> fileb
> filec
> filed
> filee
> xxx
[email protected]:/tmp/test$ cat filee
filea
fileb
filec
filed
filee

上邊的結果表示,<< 可以設置我們手動輸入時的結束字符值,而不會把設置的字符寫入到定向位置中。

幾個特殊符號

在 bash 的操作環境中,我們提到過該符號可以用來分隔連續執行的命令:

[email protected]:/tmp/test$ ls
filab  filac  filad  filea  filee
[email protected]:/tmp/test$ ll
total 12
drwxrwxr-x  2 wood wood 4096 Apr  4 23:25 ./
drwxrwxrwt 15 root root 4096 Apr  4 23:25 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood   30 Apr  4 23:25 filee
[email protected]:/tmp/test$ ls;ll
filab  filac  filad  filea  filee
total 12
drwxrwxr-x  2 wood wood 4096 Apr  4 23:25 ./
drwxrwxrwt 15 root root 4096 Apr  4 23:25 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood   30 Apr  4 23:25 filee

$?,||,&&

在 shell 中的變量我們提到過 ? 也是一個特殊的變量,該符號表示上一個命令的返回值,命令正常執行則爲0,反之則爲非0:

[email protected]:/tmp/test$ ls
filab  filac  filad  filea  filee
[email protected]:/tmp/test$ echo ${?}
0

因此可以藉由這個返回值,實現一個條件式的命令執行:

[email protected]:/tmp/test$ ls && ll
filab  filac  filad  filea  filee
total 12
drwxrwxr-x  2 wood wood 4096 Apr  4 23:25 ./
drwxrwxrwt 15 root root 4096 Apr  4 23:25 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood   30 Apr  4 23:25 filee
[email protected]:/tmp/test$ abc && ll
No command 'abc' found, did you mean:
 Command 'ab' from package 'apache2-utils' (main)
 Command 'ajc' from package 'aspectj' (universe)
 Command 'nbc' from package 'nbc' (universe)
 Command 'ac' from package 'acct' (main)
 Command 'alc' from package 'amule-utils-gui' (universe)
 Command 'axc' from package 'afnix' (universe)
 Command 'asc' from package 'asc' (universe)
 Command 'abe' from package 'abe' (universe)
 Command 'atc' from package 'bsdgames' (universe)
 Command 'abx' from package 'abx' (universe)
 Command 'aec' from package 'libaec-tools' (universe)
 Command 'cbc' from package 'coinor-cbc' (universe)
 Command 'bc' from package 'bc' (main)
 Command 'arc' from package 'arcanist' (universe)
 Command 'arc' from package 'arc' (universe)
abc: command not found
[email protected]:/tmp/test$ ls || ll
filab  filac  filad  filea  filee
[email protected]:/tmp/test$ abc || ll
No command 'abc' found, did you mean:
 Command 'asc' from package 'asc' (universe)
 Command 'atc' from package 'bsdgames' (universe)
 Command 'ab' from package 'apache2-utils' (main)
 Command 'ac' from package 'acct' (main)
 Command 'ajc' from package 'aspectj' (universe)
 Command 'bc' from package 'bc' (main)
 Command 'cbc' from package 'coinor-cbc' (universe)
 Command 'abe' from package 'abe' (universe)
 Command 'axc' from package 'afnix' (universe)
 Command 'arc' from package 'arcanist' (universe)
 Command 'arc' from package 'arc' (universe)
 Command 'aec' from package 'libaec-tools' (universe)
 Command 'alc' from package 'amule-utils-gui' (universe)
 Command 'nbc' from package 'nbc' (universe)
 Command 'abx' from package 'abx' (universe)
abc: command not found
total 12
drwxrwxr-x  2 wood wood 4096 Apr  4 23:25 ./
drwxrwxrwt 15 root root 4096 Apr  4 23:25 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood   30 Apr  4 23:25 filee

通過上邊的程序示例,基本能搞清除 || 和 && 的使用方法:

cmd1 && cmd2

cmd1 執行正常,執行 cmd2

cmd1 執行異常,不執行 cmd2

cmd1 || cmd2

cmd1 執行正常,不執行 cmd2

cmd1 執行異常,執行 cmd2

利用 || 和 && 能夠實現:

  • 如果 A 成功就執行 B
  • 如果 A 不成功就執行 B
  • 如果 A 成功就不執行 B
  • 如果 A 不成功就不執行 B

下面實現:

  • 如果 A 成功就執行 B,A 不成功就執行 C

結構爲:

A && B || C
A || C && B

採用第一種寫法驗證一下:

[email protected]:/tmp/test$ ls && ll || rm -rf *
filab  filac  filad  filea  filee
total 12
drwxrwxr-x  2 wood wood 4096 Apr  4 23:25 ./
drwxrwxrwt 15 root root 4096 Apr  4 23:25 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood   30 Apr  4 23:25 filee
[email protected]:/tmp/test$ ls
filab  filac  filad  filea  filee
[email protected]:/tmp/test$ abc && ls || ll
No command 'abc' found, did you mean:
 Command 'aec' from package 'libaec-tools' (universe)
 Command 'axc' from package 'afnix' (universe)
 Command 'atc' from package 'bsdgames' (universe)
 Command 'asc' from package 'asc' (universe)
 Command 'alc' from package 'amule-utils-gui' (universe)
 Command 'ac' from package 'acct' (main)
 Command 'ajc' from package 'aspectj' (universe)
 Command 'nbc' from package 'nbc' (universe)
 Command 'arc' from package 'arc' (universe)
 Command 'arc' from package 'arcanist' (universe)
 Command 'bc' from package 'bc' (main)
 Command 'cbc' from package 'coinor-cbc' (universe)
 Command 'abe' from package 'abe' (universe)
 Command 'abx' from package 'abx' (universe)
 Command 'ab' from package 'apache2-utils' (main)
abc: command not found
total 12
drwxrwxr-x  2 wood wood 4096 Apr  4 23:25 ./
drwxrwxrwt 15 root root 4096 Apr  4 23:25 ../
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filab
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filac
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filad
-rw-rw-r--  1 wood wood    0 Apr  4 22:49 filea
-rw-rw-r--  1 wood wood   30 Apr  4 23:25 filee
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章