
當您在 Linux 上運行 cal 時,當月的輸出將反轉視訊突出顯示當天。當我將該輸出發送到 hexdump -c 時,我得到了一些有趣的結果:
0000000 N o v e m b e r 2 0 1 6
0000010 \n S u M o T u
0000020 W e T h F r S a \n
0000030 1 2 _ \b _ \b 3
0000040 4 5 \n 6 7
0000050 8 9 1 0 1 1 1 2 \n
0000060 1 3 1 4 1 5 1 6 1 7 1
0000070 8 1 9 \n 2 0 2 1 2 2
0000080 2 3 2 4 2 5 2 6 \n 2 7
0000090 2 8 2 9 3 0
00000a0 \n
00000b0 \n
00000bc
如您所看到的,在今天反白的「3」之前列印了一個不可見的序列 _\b _\b。 _ 是底線(ascii 十六進位中的 5F),\b 是 Ctrl-H 或 ASCII 十六進位中的 08。這是什麼?我知道有很多晦澀的終端程式碼,但我希望它使用更標準的東西,例如 \e[7m.更奇怪的是,我無法透過使用標準 printf 函數(如以下命令之一)列印相同的字元來重現 cal 的相同行為:
/usr/bin/printf "1 2 _\b _\b3 4 5\n"
/usr/bin/printf "1 2 _^H _^H3 4 5\n"
其中 ^H 是按 Ctrl-V Ctrl-H 產生的。但它們都不能產生與 cal 相同的逆視頻輸出。我什至嘗試編寫一個小 C 程式來做到這一點。我也嘗試過使用 echo -e 。有趣的是,雖然它不會反轉終端中的視頻,但如果我通過 less -R 傳輸輸出,它會將其顏色更改為黃色並為其添加下劃線。在其他終端上我嘗試過它只是強調它。這看起來幾乎有點過分,但如果我使用 _ 以外的字符,它就不起作用,這讓我認為 _\b 是單一代碼序列。那麼該角色的影片如何反轉呢?
對此有何見解?
手冊頁說 cal 的輸出應該是與原始 Unix cal 指令有點相容的版本。所以我只能假設這是一些古老的程式碼。
答案1
這幾乎看起來有點過分了
正是如此。正如所討論的為什麼 80 列的控制台上有 11 個製表符?,當涉及 Unix 終端時,它有助於思考機械打字機的操作。在這種情況下,字元之前的序列_
BS(退格字元)是一種約定,用於指示該字元的下劃線,因為在某些終端上,這就是文字下劃線的方式。另一種控制序列是_
字元後的 BS。當然,在最初的終端上,什麼超越什麼並不重要。在現代視訊終端上,最後寫入的字元“獲勝”,從而擦除先前的資料。因此,_
BS <字元>順序優先。
FreeBSD ncal
,也就是這個程序,在突出顯示方面有兩種操作模式。
- 如果其輸出是終端,它將在 termcap 資料庫中尋找當前終端類型的
so
和se
序列,並在突出顯示的文字的兩側發出這些序列。 (實際上,執行此操作的程式碼中有一個錯誤,與堆疊上的緩衝區超出範圍及其內容稍後使用有關,似乎沒有人發現這一點。) - 如果它的輸出不是終端,它會發出文本,其中每個要突出顯示的字元前面都有
_
BS 序列。
你不能透過向終端發出 BS 序列來複製這一點_
,除非(當然)你的終端是這樣強調內容的終端之一。終端模擬器不是這種情況,幾乎可以肯定,您在這裡使用的任何終端或終端模擬器都不是這種情況。
但是,您可以篩選透過程式使用此約定的文本,ul
該程式識別此約定以及其他幾個類似打字機的約定,並將它們轉換為終端實際的控制序列,並在 termcap 資料庫中查找它們。您也可以printf
透過過濾命令的輸出ul
。
在其他終端上我嘗試過它只是強調它。
ncal
諷刺的是,透過程式過濾非終端模式輸出ul
實際上比讓ncal
編寫終端控制序列本身稍好一些。而ncal
使用終端的脫穎而出模式,ul
將嘗試使用終端的實際強調轉換 BS 序列時的模式(如果有)_
。如 termcap 手冊所解釋的,突出模式可以是任何適合終端的模式(包括粗體、反向視訊或顏色),且不一定是底線。在您的一個終端上,它顯然是下劃線和顏色變化的組合。
此外,ul
還可以處理沒有下劃線開始/結束序列但有下劃線最後一個字元序列的終端。諷刺的是,ul
如果您的終端能夠應對真的是_
一個在每個字元後面加上 BS 來強調的,而ncal
無法應對。
當然,ul
沒有ncal
緩衝區處理錯誤。 ☺
如果我將輸出通過管道傳輸到
less -R
,它會將其顏色更改為黃色並為其添加下劃線。
正如您所發現的,該less
程式理解_
BS 序列並按照ul
程式的方式處理它們。並不完全一樣。 ul
可以處理涉及多個 BS 字元的序列_
,也可以處理類似的粗體字元序列。 less
不能。對比一下您從這兩者中看到的情況:
/usr/bin/printf "1 2 ______\b\b\b\b\b\b 3 _\b4.\b\b\b45 6\n" |烏爾
/usr/bin/printf "1 2 ______\b\b\b\b\b\b 3 _\b4.\b\b\b45 6\n" |較少的
回到過去的美好時光
可悲的是,這些仍然是「美好的舊時光」。不要讓人們欺騙您,讓您相信現在很少使用此功能。
它不在手冊中,但原始程式碼指出ul
它正在嘗試實作 Teletype Model 37 的控制序列處理,因為「這就是輸出nroff
」。原始 Unix 程式的 GNU 替代品nroff
是在終端獲得顏色、粗體和斜體等奇特功能很久之後編寫的,能夠生成ECMA-48顏色、粗體和斜體的控制序列。它實際上是這樣做的在正常情況下。
nroff
及其 GNU 替代品用於格式化手冊頁以在終端機上顯示。可悲且諷刺的是,從它編寫大約10 年後開始,人們開始對GNU 工具進行修改,使其生成1968 年的舊Teletype Model 37 序列,而不是1976 年的“新”ECMA-48 控制序列(原文如此!他們使用修改其預設行為的選項進行man
調用groff
,並添加強制額外 ditroff 輸出的未記錄檔案。
每次您在終端機上閱讀手冊頁時,手冊系統都會運行groff
,該系統會盡職盡責地將手冊來源文字轉換為使用這些舊的 Teletype Model 37 控制序列的輸出字元流,這些控制序列less
或more
正在轉換為終端的控制序列。
進一步閱讀
答案2
Ctrl-H
是退格鍵,它將遊標向左移動一步。在過去的好日子裡,發送下劃線、退格鍵和其他一些字元是在硬拷貝(“紙質”)終端上給某些內容加下劃線的方法。這用於在 的輸出中突出顯示當天cal
。
我的cal
程式在運行時konsole
不會輸出此序列。如果我運行script -c cal
並檢查生成的typescript
文件,我可以看到 cal 程式使用轉義序列<esc>[7m
切換到反轉模式影片。