Shell 標準輸入和輸出

来源:https://www.cnblogs.com/jiagooushi/archive/2022/12/15/16985019.html
-Advertisement-
Play Games

無論是要交給程式處理的數據,還是控制腳本的簡單命令,都少不了輸入和輸出。程式要做的第一件事就是處理如同一陰一陽的“輸入與輸出”。 1 、從文件獲取輸入 當我們希望向文件輸出內容時,我們可以通過符號 > 或 >> 實現。而用代表輸入重定向的符號 < 可以從文件中讀取數據,如下: $ wc < my.f ...


無論是要交給程式處理的數據,還是控制腳本的簡單命令,都少不了輸入和輸出。程式要做的第一件事就是處理如同一陰一陽的“輸入與輸出”。

1 、從文件獲取輸入

當我們希望向文件輸出內容時,我們可以通過符號 > 或 >> 實現。而用代表輸入重定向的符號 < 可以從文件中讀取數據,如下:

$ wc < my.file

之所以選擇這種形狀的操作符號,原因在於它們可以從視覺上提示重定向的方向。

很多 shell 命令可以接受一個或多個文件名作為參數,但如果沒有給出文件名,命令就會從標準輸入讀取。使用這種命令時,可以採用command filename 或者 command < filename,這兩種形式的結果沒什麼區別。在這個例子中,wc 是這樣,換作 cat 或其他命令,也是如此。

2、將數據與腳本存放在一起

< 可以從文件讀取數據,當你需要獲得腳本輸入,但又不想用單獨的文件時,使用 <<(here-document)從命令行而非文件重定向輸入文本。如果放在 shell 腳本中,則腳本文件可以同時包含數據與代碼。

以下是名為 ext.sh 的 shell 腳本示例:

# 下麵是here-document
grep $1 <<EOF

mike x.123

joe x.234

sue x.555

pete x.818

sara x.822

bill x.919

EOF

當我們運行此腳本,可以傳入一個參數,如下調用:

$ ./ext.sh bill
# 輸出以下內容
bill x.919

grep 命令查找第一個參數是否在指定文件中出現,如果沒有指定文件,那麼它會在標準輸入中查找。通過設置 here document,告訴 shell 將標準輸入重定向(臨時)到此處。<< 語法表示我們想創建一個臨時輸入源,EOF 是一個任意的字元串(你想用什麼都行),用作臨時輸入的終止符。它並不屬於輸入的一部分,只是作為標記告訴輸入在哪裡結束。

3、避免here-document中的怪異行為

here-document 在使用時可能會出現一些怪異的行為。你想用上一節介紹的方法來保存一份簡單的捐贈人列表,因此創建了一個名為donors.sh 的文件,如下所示:

# 簡單地查找慷慨的捐贈人

grep $1 <<EOF

pete $100

joe $200

sam $ 25

bill $ 9

EOF

但是運行時出現了奇怪的輸出:

$ ./donors.sh bill

pete bill00

bill $ 9

$ ./donors.sh pete

pete pete00

正常情況下(除非使用了轉義語法),bash 手冊頁中是這樣說的:“……here-document 的每一行都要執行參數擴展、命令替換以及算術擴展”。因此,最初的 donors 腳本中所發生的事情是捐贈額被當作 shell 變數了。例如,$100 被視為 shell 變數 $1,隨後跟著兩個 0。這就是為什麼我們在搜索“pete”時,得到的是 pete00;搜索“bill”時,得到的是 bill00。

解決辦法:

通過轉義結尾標記中的任意或所有字元,修改腳本內容,關閉 here-document 內部的 shell 特性(註意觀察EOF位置的變化):

# 簡單地查找慷慨的捐贈人
grep $1 <<'EOF'

pete $100

joe $200

sam $ 25

bill $ 9

EOF

儘管其中存在非常微妙的區別,但也可以將 <<EOF 替換成 <<\EOF或 <<'EOF',甚至是 <<E\OF,都沒問題。儘管這並不是最優雅的語法,但足以告訴 bash 你希望區別處理 here-document 中的內容。如果我們轉義了 EOF 的部分或全部字元,那麼 bash 就知道不用執行擴展,這樣就符合我們的預期行為了。

$ ./donors.sh pete

pete $100

4、獲取用戶輸入

輸入不止從文件中獲取,有時我們還需要獲取用戶輸入的內容。此時,我們需要用到read命令,如下:

$ read

或者

$ read -p "answer me this " ANSWER

不帶參數的 read 語句會讀取用戶輸入並將其保存在 shell 變數REPLY 中,這是 read 的最簡形式。如果希望 bash 在讀取用戶輸入前先輸出提示信息,可以使用 -p 選項。-p 之後的單詞就是提示信息,如果想提供多個單詞,可以將其引用起來。記住,要在提示信息結尾處加上標點符號或空格,因為游標會停在那裡等待輸入。-t 選項可以設置超時值。指定秒數達到後,不管用戶是否輸入,read 語句都會返回。我們的示例同時用到了 -t 和 -p 選項,但你也可以單獨使用 -t 選項。

上面的方式獲取用戶輸入時會以明文回顯,那適用密碼輸入麽?

當我們需要用戶輸入敏感信息時,需要禁止用戶輸入內容的回顯。此時用 read 命令讀取用戶輸入,需要加上一個特殊選項來關閉回顯:

read -s -p "password: " PASSWD

printf "%b" "\n"

-s 選項告訴 read 命令不要回顯輸入的字元(s 代表 silent),-p 選項指明下一個參數是提示信息,會在讀取用戶輸入之前顯示。從用戶那裡讀取到的輸入行保存在變數 $PASSWD 中。在 read 之後,我們用 printf 輸出了一個換行符。這裡的printf 不能少,因為 read -s 會關閉字元回顯。如果禁止了回顯功能,當用戶按下回車鍵時,就不會回顯換行符,後續輸出就會和提示信息出現在同一行。輸出換行符會將游標帶到下一行。

當然,我們也可以選擇一行,如下:

read -s -p "password: " PASSWD ; printf "%b" "\n"

Shell標準輸出

如果無法產生輸出,那麼軟體也就沒什麼價值了,但長久以來,I/O一直是難纏的計算領域之一。問題是有太多類型的輸出,向屏幕寫入不同於向文件寫入,向文件寫入也不同於向磁帶或快閃記憶體寫入。所以,對於輸出會產生一些問題,如下:

  • 軟體開發人員是否要針對各種輸出設備編寫代碼,甚至包括尚未發明的設備?
  • 寫到哪個文件?程式怎麼知道是該寫入代表終端視窗的文件、磁碟文件還是其他種類的文件?

顯然,如果把這些事情都交給每個程式員是不合理的,所以這種事情留給shell 就行了。

1、輸出到終端/終端視窗

想要用 shell 命令產生一些簡單的輸出,使用內建命令 echo。命令行中的所有參數都會列印到屏幕上。

echo Please wait.

輸出:

Please wait.

結果和在 bash 提示符(字元 $)後輸入該命令相同:

file

echo 是最簡單的 bash 命令之一。該命令可以將參數輸出到屏幕上。但是有幾點需要記住:

  • 首先,shell 負責解析 echo 的命令行參數。將參數交給 echo前,shell 會完成所有的替換、通配符匹配等操作。
  • 其次,在解析參數時,參數之間的空白字元會被忽略,如下圖:

file

shell 對參數間的空白字元沒有太多限制,這通常是一種不錯的特性。但對於 echo 來說,就有點煩人了。

  • 保留輸出中的空白字元。將字元放入引號中就可以保留空白字元,如下圖:

file

引號中的單片語成了 echo 命令的單個參數。該參數是一個字元串,shell 不會幹涉字元串的內容。實際上可以用單引號('')明確告訴shell 不要干涉字元串。

2、在輸出中加入更多格式控制

使用內建命令 printf。例如:

printf '%s = %d\n' Lines $LINES
Lines = 24

或者:

$ printf '%-10.10s = %4.2f\n' 'Gigahertz' 1.92735

Gigahertz = 1.93

內建命令 printf 的行為和 C 語言中的同名庫函數相似,其中第一個參數是格式控制字元串,之後的參數都根據格式規範(%)進行格式化。

% 和格式類型(本例為 s 或 f)之間的數字提供了額外的格式化細節。

對於浮點類型(f),第一個數字(指示符 4.2 中的 4)是整個欄位的寬度。第二個數字(2)是應該在小數點右側列印出的數位量。註意,結果會按照四捨五入處理。

對於字元串,第一個數字是欄位的最大寬度,第二個數字是要輸出的字元數量。根據需要,字元串會被截斷(長於 max)或用空白填充(不足 min)。如果指示符 maxmin 相同,那麼就可以確保字元串按照該長度輸出。指示符左側的負號表示字元串向左對齊(在欄位寬度內)。如果不使用負號,則字元串向右對齊

3、消除輸出中的換行符

希望輸出中不包含 echo 預設生成的換行符。使用 printf,做法很簡單,去掉格式化字元串末尾的 \n 即可,如下圖:

printf "%s %s" next prompt

file

如果是 echo,則使用 -n 選項:

$ echo -n prompt

file

因為 printf 的格式字元串(第一個參數)末尾並沒有換行符,所以命令行提示符($)出現在了 printf 的輸出之後。該特性在shell 腳本中用處更大,你可能希望在形成一整行前由多條語句逐部分輸出,或者在讀取輸入前顯示用戶提示。

換作 echo 命令(參見 15.6 節),消除換行符的方法有兩種。

首先,-n 選項能夠抑制輸出行尾的換行符。

另外,echo 命令還可以處理多種具有特殊含義的轉義序列(如表示換行符的 \n),這些轉移序列與 C 語言字元串中的類似。調用 echo 命令時加上 -e 選項。其中一種轉義序列是 \C,它並不會輸出什麼字元,而是禁止在行尾輸出換行符。如下圖:

$ echo -e 'hi\c'

file

4、保存命令輸出

如過想把命令輸出保存在文件中,用 > 符號告訴 shell 將輸出重定向至文件,例如:

$ echo fill it up

fill it up

$ echo fill it up > file.txt

我們來查看一下文件 file.txt 的內容,看看其中是否包含了命令的輸出:

$ cat file.txt

fill it up

示例第一部分的第一行中出現的 echo 命令包含了 3 個要輸出的參數。第二行用 > 將這些輸出保存到文件 file.txt 中,這就是看不

到 echo 輸出的原因。

示例第二部分用 cat 命令顯示文件內容。我們可以看出,文件中包含的正是 echo 本該輸出的內容。

cat 命令得名自一個較長的單詞 concatenation(拼接)。該命令會將出現在命令行上的文件的輸出拼接在一起,如果你輸入 cat

file1 file2 file3,那麼這些文件的內容會逐個發送到終端視窗。如果一個大文件被分成了兩半,你也可以用 cat 將其恢複原樣(也就是將兩部分拼接起來),這隻需將輸出保存到另一個文件中:

cat first.half second.half > mergeFile.txt

5、將輸出保存到其他文件

如想要用重定向將輸出保存到當前目錄之外的其他位置,重定向輸出時加上路徑,如下:

echo some more data > /tmp/echo.out

或者:

echo some more data > ../../over.here

出現在重定向符號(>)後的文件名其實就是路徑名。如果沒有任何限定部分,那麼文件就會放置在當前目錄中。

如果文件名以斜線(/)起始是絕對路徑名,此時文件會被放置在文件系統層次結構(目錄樹)中以根目錄起始的指定位置。

第二個例子中,我們使用了相對路徑名 ../../over.here,其中的.. 是一個指向父目錄的特殊目錄,存在於每個目錄中。

6、將輸出和錯誤消息發送到不同文件

希望獲得程式的輸出,但不想輸出被出現的錯誤消息弄亂。要保存的錯誤消息混雜在程式輸出中不容易找出,可將輸出和錯誤消息重定向到不同文件,如下:

$ myprogram 1> messages.out 2> message.err

或者採用更常見的方法:

$ myprogram > messages.out 2> message.err

shell 會創建兩個輸出文件。

第一個是messages.out,程式 myprogram 的所有輸出都會重定向到該文件。

第二個是message.err,程式myprogram 的所有錯誤消息都會重定向到 message.err。

在 1> 和 2> 中,數字表示文件 描述符。

  • 1 代表標準輸出(STDOUT),
  • 2 代表標準錯誤(STDERR)。
  • 0 代表標準輸入(STDIN)。

如果不指定數字,則假定為 STDOUT。

7、將輸出和錯誤消息發送到同一文件

利用重定向,我們可以將輸出或錯誤消息保存到單獨的文件中,但如何將兩者送往同一文件呢?用 shell 語法將標準錯誤消息重定向到和標準輸出相同的地方。

首選:

$ myprogram >& outfile

或者:

$ myprogram &> outfile

又或者老式且略煩瑣的寫法:

$ myprogram > outfile 2>&1

其中,myprogram是準備向 STDERR 和 STDOUT 生成輸出的程式。

&> 和 >& 只是將 STDOUT 和 STDERR 發送到相同地方的便捷寫法。

8、追加輸出

每次重定向輸出,都會產生一個全新的輸出文件。如果想要兩次(或三次、四次……)重定向輸出,同時又不想破壞之前的輸出,該怎麼辦呢?

在 bash 的重定向符號中,雙大於號(>>)表示追加輸出:

$ ls > /tmp/ls.out
$ cd ../elsewhere
$ ls >> /tmp/ls.out
$ cd ../anotherdir
$ ls >> /tmp/ls.out

如果存在同名文件,第一行中的重定向會將其截斷,並將 ls 命令的輸出保存在這個已被清空的文件中。

後兩次調用 ls 時使用了雙大於號(>>),表示向輸出文件中追加內容,而不是覆蓋其原有內容。

如果想要同時重定向錯誤消息(STDERR),可以將 STDERR 的重定向放在後面,如下所示:

ls >> /tmp/ls.out 2>&1

在 bash 4 中,你可以將這兩個重定向合二為一:

$ ls &>> /tmp/ls.out

該命令會重定向 STDERR 和 STDOUT,並將兩者追加到指定文件中。& 符號必須先出現,且這 3 個字元之間不能有空格

9、丟棄輸出

你有時不想將輸出保存到文件中或者有時甚至不想看到輸出。如我們在查找某個文件時,忽略那些沒有許可權的提示,如下圖:

file
此時,我們可以將輸出重定向到 /dev/null,如下所示:

$ find / -name myfile 2> /dev/null

其實,你可以將不想要的輸出重定向到文件,然後再將其刪除。但還有一個更簡單的方法。Unix 和 Linux 系統都存在一個特殊設備,該設備並非真實的硬體,而僅僅是一個位桶(bit bucket),我們可以將不需要的數據都扔進去。它就是 /dev/null,非常適用於此類場景。寫入其中的數據會被直接丟棄並不會占用磁碟空間,重定向很容易做到這一點。示例中,只有發往標準錯誤的輸出被丟棄了

本文由傳智教育博學谷教研團隊發佈。

如果本文對您有幫助,歡迎關註點贊;如果您有任何建議也可留言評論私信,您的支持是我堅持創作的動力。

轉載請註明出處!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 標準容器->容器適配器 什麼叫適配器? 1:適配器底層沒有自己的數據結構,它是另外一個容器的封裝,它的方法, 全部由底層依賴的容器進行實現的.像標準庫中的stack 如下圖 2:沒有實現自己的迭代器 容器適配器 stack,queue,priotity_queue 沒有迭代器 stacks1; 棧, ...
  • 1.控制語句 1.1.判斷語句 if...elif...else #if 語句(比較/邏輯/成員均可) #字元串/列表/元組/字典 為空返回False,非空返回True #條件成立返回True,不成立返回False ar = "" list = [] tuple = () dic = {} if a ...
  • 如何開發微信小程式 小程式:學習微信開發的語言(前端html、css、js、vue.js) 微信開發者工具 API:restful介面(Python+django+drf框架)。 pycharm 環境搭建 python環境搭建 虛擬環境 django drf pycharm 小程式環境 在微信公眾平 ...
  • data analysis 什麼是數據分析 是把隱藏在一些看似雜亂無章的數據背後的信息提煉出來,總結出所研究對象的內在規律 使得數據的價值最大化 分析用戶的消費行為 制定促銷活動的方案 制定促銷時間和粒度 計算用戶的活躍度 分析產品的回購力度 分析廣告點擊率 決定投放時間 制定廣告定向人群方案 決定 ...
  • LVS 負載均衡 本篇主要介紹一下 lvs 是什麼 以及它的 nat 模式的搭建 配合nginx來演示 1.概述 LVS 是 Linux Virtual Server 的簡寫 (Linux 虛擬伺服器 ), 是由章文嵩博士主導, 它虛擬出一個伺服器集群,然後進行負載均衡的項目, 目前LVS 已經被集 ...
  • Linux常用命令 1、 關機/重啟/註銷 | 常用命令 | 作用 | | | | | shutdown -h now | 即刻關機 | | shutdown -h 10 | 10分鐘後關機 | | shutdown -h 11:00 | 11:00關機 | | shutdown -h +10 | ...
  • 最近在複習以前學習的python爬蟲內容,就拿微博來練了一下手,這個案例適合學習爬蟲到中後期的小伙伴,因為他不是特別簡單也不是很難,關鍵是思路,為什麼說不是很難呢?因為還沒涉及到js逆向,好了話不多說開乾。 (1)找到要爬取的頁面,如下: (2)點開評論,拉到最下方,如下位置: 點擊“點擊查看”進入 ...
  • 來源:developer.aliyun.com/article/889271 本文準備圍繞七個點來講網關,分別是網關的基本概念、網關設計思路、網關設計重點、流量網關、業務網關、常見網關對比,對基礎概念熟悉的朋友可以根據目錄查看自己感興趣的部分。 什麼是網關 網關,很多地方將網關比如成門, 沒什麼問題 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...