Quando a saída do comando cal
não é um terminal, aplica-se o sublinhado do homem pobre ao número do dia de hoje, que consiste em colocar um sublinhado e um caractere de retrocesso antes que cada caractere seja sublinhado. Você pode ver isso exibindo os caracteres visualmente ( ^H
significa control-H , que é o caractere de retrocesso) :
cal | cat -A
cal | cat -vet
ou olhando para um despejo hexadecimal:
cal | hd
cal | od -t x1
Então, o que você precisa é detectar os caracteres sublinhados e gerá-los.
Com o GNU grep, existe uma maneira fácil de imprimir todas as correspondências de uma expressão regular: use a opção -o
. Um caractere sublinhado é correspondido pela expressão regular estendida _^H.
em que ^H
é um caractere de retrocesso literal, não os dois caracteres ^
e H
e .
é o caractere a ser impresso. Em vez de digitar o caractere de retrocesso, você pode confiar no fato de que essa é a única maneira de usar sublinhados em sua saída. Portanto, basta detectar os sublinhados e deixar os espaços de retorno como caracteres não correspondentes.
cal | grep -o '_..'
Estamos próximos, mas a saída contém a sequência sublinhado-barra invertida e os dígitos estão em linhas separadas. Você pode remover todos os caracteres não digitados (e adicionar uma nova linha):
cal | grep -o '_..' | tr -d 0-9; echo
Como alternativa, você pode repetir o padrão _..
para corresponder a vários dígitos sublinhados. Isso deixa o sublinhado na saída, você pode usar tr ou sed para retirá-lo.
cal | grep -E -o '(_..)*'
cal | grep -E -o '(_..)*' | tr -d '\b_'
cal | grep -E -o '(_..)*' | sed 's/_.//g'
Você pode fazer isso com sed, mas não é completamente simples. O Sed oferece uma maneira fácil de imprimir apenas linhas correspondentes (use a opção -n
para obter apenas linhas que são impressas explicitamente), mas nenhuma maneira direta de imprimir várias ocorrências de uma correspondência em uma linha. Uma maneira de resolver isso é aproveitar o fato de que há no máximo dois caracteres sublinhados e ter um comando s
para transformar e gerar linhas contendo um único caractere sublinhado e outro para linhas com dois. Como antes, não corresponderei explicitamente aos backspaces.
cal | sed -n 's/.*_.\(.\)_.\(.\).*//p; s/.*_.\(.\).*//p'
Uma abordagem alternativa com sed, supondo que há apenas um segmento sublinhado em uma linha, é remover tudo antes e depois dele.
cal | sed -n 's/^[^_]*_/_/; s/\(_..\)[^_]*$//p'
Isso deixa os sublinhados; podemos removê-los com um terceiro substituto.
cal | sed -n 's/^[^_]*_/_/; s/\(_..\)[^_]*$//; s/_.//gp'