Command-Line

使用 cal 輸出目前日期

  • January 12, 2019

我被要求使用該cal命令輸出目前日期。

到目前為止,我發現在目前日期之前有一個_符號。我決定在grep這裡使用:cal | grep '\b_*',但它會輸出整個星期。我嘗試了幾種變體,但都沒有成功。

其實還有一種情況,當日只有一位時,看來我必須在tr -d ' '這裡使用。

我不知道如何將所有這些命令組合在一起。

cal命令的輸出不是終端時,它會將窮人的下劃線應用於今天的日期編號,其中包括在每個字元之前放置一個下劃線和一個退格字元來進行下劃線。您可以通過直覺地顯示字元來看到這一點(^H表示control-H,即退格字元):

cal | cat -A
cal | cat -vet

或通過查看十六進制轉儲:

cal | hd
cal | od -t x1

所以你需要的是檢測帶下劃線的字元並輸出它們。

使用 GNU grep,有一種簡單的方法可以列印正則表達式的所有匹配項:使用-o選項。下劃線字元由擴展的正則表達式匹配,_^H.其中^H是文字退格字元,而不是兩個字元^H,並且.是要列印的字元。無需鍵入退格字元,您可以依靠這是 cal 在其輸出中使用下劃線的唯一方式這一事實。所以檢測下劃線並將退格保留為不匹配的字元就足夠了。

cal | grep -o '_..'

我們很接近,但輸出包含下劃線反斜杠序列,並且數字位於不同的行上。您可以刪除所有非數字字元(並添加回尾換行符):

cal | grep -o '_..' | tr -d 0-9; echo

或者,您可以重複該模式_..以匹配多個帶下劃線的數字。這會在輸出中留下下劃線,您可以使用 tr 或 sed 將其剝離。

cal | grep -E -o '(_..)*'
cal | grep -E -o '(_..)*' | tr -d '\b_'
cal | grep -E -o '(_..)*' | sed 's/_.//g'

您可以使用 sed 執行此操作,但這並不完全簡單。Sed 提供了一種僅列印匹配行的簡單方法(使用該-n選項僅獲取顯式列印的行),但沒有直接的方法可以在一行上列印多個匹配項。解決此問題的一種方法是利用最多有兩個下劃線字元這一事實,並使用一個s命令來轉換和輸出包含單個下劃線字元的行,而另一個命令用於轉換和輸出包含兩個下劃線字元的行。和以前一樣,我不會明確匹配退格鍵。

cal | sed -n 's/.*_.\(.\)_.\(.\).*/\1\2/p; s/.*_.\(.\).*/\1/p'

使用 sed 的另一種方法是,假設一行中只有一個帶下劃線的段,即刪除它之前的所有內容和之後的所有內容。

cal | sed -n 's/^[^_]*_/_/; s/\(_..\)[^_]*$/\1/p'

這留下了下劃線;我們可以通過第三次替換來刪除它們。

cal | sed -n 's/^[^_]*_/_/; s/\(_..\)[^_]*$/\1/; s/_.//gp'

正確的方法是使用date

% date +%d
19

您看到的下劃線不是下劃線,而是終端顯示的控製字元。如果你真的想使用cal,你需要找出那個控製字元是什麼並尋找它。您可以通過使用類似的東西來使用它cal | xxd

另一個問題是,cal只有當 stdout 是 tty 時才輸出這個控製字元,所以你需要說服它是一個(考慮script這個)。

引用自:https://unix.stackexchange.com/questions/346153