我被要求使用该命令输出当前日期cal
。
到目前为止,我发现当前日期之前有一个_
符号。我决定在这里使用grep
:cal | grep '\b_*'
,但它输出整个星期。我尝试了几种变体,但没有成功。
实际上,还有一种情况,当前日期只有一位数字,所以看来我必须tr -d ' '
在这里使用。
我不知道如何将所有这些命令组合在一起。
答案1
执行此操作的正确方法是使用date
:
% date +%d
19
您看到的下划线不是下划线,而是终端显示的控制字符。如果你真的想要使用cal
,你需要找出那个控制字符是什么并寻找它。您可以通过使用类似的东西来使用它cal | xxd
。
另一个问题是,cal
仅当 stdout 是 tty 时才输出此控制字符,因此您需要说服它它是一个(请考虑script
这一点)。
答案2
当命令的输出cal
不是终端时,它会将穷人的下划线应用于今天的天数,其中包括在每个要下划线的字符之前添加一个下划线和一个退格字符。您可以通过直观地显示字符来看到(^H
意味着控制-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'
答案3
我现在不在 GNU cal 命令前面,但这更接近你想要的:
cal | grep -Eo '_[[:digit:]]+' | sed 's/_//'
grep-E
表示允许扩展正则表达式(对于 [[:digit:]] 类);该-o
标志表示仅输出匹配部分; sed 命令删除下划线。
这是 cal + grep 的方法,但是作为克里斯说,获取当前日期的正常方法是使用命令date
。
答案4
cal | cat -vet | grep -o "H....." | cut -c 2,6
简单且效果良好,尽管这不是最好的方法。