Exibindo o número da semana em determinado formato usando ncal ou cal

14

Você não adora quando dois comandos fazem uma coisa que você quer, mas não os dois?

Isso é o que o cal faz. Formatação agradável. Não tem números de semana:

$ cal
    January 2012      
Su Mo Tu We Th Fr Sa  
 1  2  3  4  5  6  7  
 8  9 10 11 12 13 14  
15 16 17 18 19 20 21  
22 23 24 25 26 27 28  
29 30 31              

Isso é o que o ncal faz. Formatação estranha, mas com números de semana:

$ ncal -w
    January 2012      
Su  1  8 15 22 29   
Mo  2  9 16 23 30   
Tu  3 10 17 24 31   
We  4 11 18 25      
Th  5 12 19 26      
Fr  6 13 20 27      
Sa  7 14 21 28      
    1  2  3  4  5   

O tipo de saída que desejo, na verdade, um cruzamento entre cal e ncal -w :

$ cal --magik-calendar-week-option
      January 2012      
   Su Mo Tu We Th Fr Sa  
1   1  2  3  4  5  6  7  
2   8  9 10 11 12 13 14  
3  15 16 17 18 19 20 21  
4  22 23 24 25 26 27 28  
5  29 30 31
    
por k0pernikus 19.01.2012 / 10:53

8 respostas

11

Se nenhum desses comandos atender às suas necessidades, você poderá usar gcal para fazer o que quiser.

Exemplo

$ gcal -K

      April 2014
 Su Mo Tu We Th Fr Sa CW
        1  2  3  4  5 13
  6  7  8  9 10 11 12 14
 13 14 15 16 17 18 19 15
 20 21 22 23 24 25 26 16
 27 28 29 30          17

Imprime o número da semana na última coluna à direita.

Referências

por 28.04.2014 / 18:31
9

Isso destaca a data de hoje e pode exibir qualquer mês por meio de $1 no formulário: YYYY-mm-dd ... O padrão é a data de hoje

Está configurado para mostrar os números da semana ISO e o primeiro dia da semana é a segunda-feira.

#!/bin/bash
# Input reference date is expected in  'YYYY-mm-dd' format
#
today=($(date '+%Y %m %d')); Y=0; m=1; d=2                # establish today's date
[[ -z $1 ]] && ref=(${today[@]}) || ref=(${1//-/ })       # get input date
dNbA=$(date --date="$(date +%Y-%m-01)" +'%u')             # day-number of 1st day of reference month
today[m]=$((10#${today[m]})); ref[m]=$((10#${ref[m]}))    # remove leading zero (octal clash)
today[d]=$((10#${today[d]})); ref[d]=$((10#${ref[d]}))    # remove leading zero (octal clash)
nxtm=$(( ref[m]==12 ?1       :ref[m]+1 ))                 # month-number of next month
nxtY=$(( ref[m]==12 ?ref[Y]+1:ref[Y]   ))                 # year-number of next month
nxtA="$nxtY-$nxtm-1"                                      # date of 1st day of next month
refZ=$(date --date "$(date +$nxtA) yesterday" +%Y-%m-%d)  # date of last day of reference  month
days=$(date --date="$refZ" '+%d')                         # days in reference month

h1="$(date --date="${ref[Y]}-${ref[m]}-${ref[d]}" '+%B %Y')" # header 1 
h2="Mo Tu We Th Fr Sa Su"                                    # header 2 
printf "    %$(((${#h2}-${#h1}-1)/2))s%s\n" " " "$h1"
printf "    %s\n" "$h2"
# print week rows   
printf "%2d  " "$((10#$(date -d "$(date +${ref[Y]}-${ref[m]}-01)" +'%V')))" # week-number (of year) with suppressed leading 0
printf "%$(((dNbA-1)*3))s"  # lead spaces (before start of month)
dNbW=$dNbA  # day-number of week
dNbM=1      # day-number of month
while ((dNbM <= days)) ;do
    if (( today[Y]==ref[Y] &&  
          today[m]==ref[m] && 
          today[d]==dNbM )) ;then
        printf "\x1b[7m%2d\x1b[0m " "$dNbM" # highlight today's date 
    else
        printf "%2d " "$dNbM"
    fi
    ((dNbM++))
    if ((dNbW  >=7)) ;then
        cdate=$((10#$(date -d "$(date +${ref[Y]}-${ref[m]}-$dNbM)" +'%V'))) # remove leading zero (octal clash)
        printf "\n%2d  " "$cdate" # week-number of year
        dNbW=0
    fi
    ((dNbW++))
done
printf "%$(((8-dNbW)*3))s\n" # trailing spaces (after end of month)

Aqui está a exibição deste mês (com 20 em destaque)

       January 2012
    Mo Tu We Th Fr Sa Su
52                     1 
 1   2  3  4  5  6  7  8 
 2   9 10 11 12 13 14 15 
 3  16 17 18 19 20 21 22 
 4  23 24 25 26 27 28 29 
 5  30 31                
    
por 19.01.2012 / 12:30
7

Você pode usar nl para numerar as linhas (essa é a finalidade do programa :). Mas você precisa extrair a primeira semana do mês de algum lugar. Isso pode ser feito a partir do ncal :

$ ncal -w 2 2012 | tail -1 | awk '{print $1}'
5

Inserimos isso como um parâmetro para a opção nl -v (número da linha inicial) e informamos apenas as linhas numéricas com números ou espaços.

$ cal 2 2012 | nl -bp'^[0-9 ]\+$' -w2 -s'  ' -v$(ncal -w 2 2012 | tail -1 | awk '{print $1}')
       February 2012
    Su Mo Tu We Th Fr Sa
 5            1  2  3  4
 6   5  6  7  8  9 10 11
 7  12 13 14 15 16 17 18
 8  19 20 21 22 23 24 25
 9  26 27 28 29

Isso tudo é muito frágil. De qualquer forma, se você não vai precisar das opções mais avançadas do cal , ele funcionará. Você pode colocá-lo em um arquivo e substituir "$@" onde eu coloquei 2 2012 .

EDIT: Mas isso é ERRADO! Eu só notei que a primeira semana de janeiro pode ter o número 52 ou 53! Por isso, temos que abrir uma exceção para janeiro ou apenas extrair all os números das semanas de ncal e aplicá-los à saída de cal .

Esta é a solução que pensei originalmente, mas pensei (erroneamente) que simplificaria usando nl . Ele usa paste , que mescla arquivos lado a lado. Como não há arquivos, temos que usar o bashism <(...) ; é o que eu estava tentando evitar.

Nosso primeiro "arquivo" será uma lista dos números da semana, com duas linhas vazias no começo:

$ printf '   \n   \n' && printf '%2d \n' $(ncal -w 1 2011 | tail -1)


52
 1
 2
 3
 4
 5

O segundo, apenas a saída de cal . Todos juntos, como parâmetros para paste :

$ paste -d' ' <(printf '   \n   \n' && printf '%2d \n' $(ncal -w 1 2011 | tail -1)) <(cal 1 2011)
        January 2011
    Su Mo Tu We Th Fr Sa
52                     1
 1   2  3  4  5  6  7  8
 2   9 10 11 12 13 14 15
 3  16 17 18 19 20 21 22
 4  23 24 25 26 27 28 29
 5  30 31

Muito messier e incompatível que o outro. En fin ...

    
por 19.01.2012 / 11:52
5

Gere a sequência de semanas com ncal e use paste para ter as duas saídas lado a lado.

$ paste <(echo; echo; ncal -w | tail -1 | xargs -n1 printf '%2d\n') <(cal)

Se você não gosta de ter guias como delimitadores, basta adicionar algo como sed 's/\t/ /'

Editar : muito mais simples, não precisa se preocupar com guias:

$ paste -d' ' <((echo -n '   '; ncal -w | tail -1 )| fold -w 3) <(cal)
    
por 19.01.2012 / 17:39
4

Uma maneira de usar o Perl (meu idioma de saída do comando cal é espanhol, mas espero que o resultado não varie de inglês):

$ cal | perl -pe 'if ( m/\A\s*\d/ ) { s/\A/++$i . qq[ ] x 2/e } else { s/\A/qq[ ] x 3/e }'

Saída:

       enero de 2012   
   lu ma mi ju vi sá do
1                     1
2   2  3  4  5  6  7  8
3   9 10 11 12 13 14 15
4  16 17 18 19 20 21 22
5  23 24 25 26 27 28 29
6  30 31

Explicação:

-pe                     # For every input line from previous pipe, execute  next
                        # instructions and print to output.
if ( m/\A\s*\d/ )       # If line begins with a digit omitting spaces...
s/\A/++$i . qq[ ] x 2/e # Insert at the beginning of the line a counter plus two spaces.
else                    # else...
s/\A/qq[ ] x 3/e        # Insert three spaces at the beginning of the line.
    
por 19.01.2012 / 11:33
1

Sem representante suficiente para comentar a resposta , por slm, gcal pode ser instalado no Mac OS usando brew install gcal .

(Eu encontrei a resposta aqui primeiro, então esta resposta em perguntar diferente, mas a resposta unix faltava todas as informações que eu precisava para instalar no mac.)

    
por 13.03.2018 / 20:03
0

Aqui está minha solução, que é mais curta no código e funciona bem para outras datas além do mês atual. Desculpe pelo povo dos EUA, isso usa o formato ISO, ou seja, primeiro dia da semana é segunda-feira. Isso é feito com a opção -m para cal e a opção% V para data

#!/bin/bash
if [ "$1" = "" ]
then
  when="now"
else
  when="$1"
fi
y=$(date --date "$when" +%Y )
if [ $? -ne 0 ]
then
  exit
fi
m=$(date --date "$when" +%m )
w=$(date --date $(printf %4d%02d01 $y $m) +%V)
cal -m $m $y |
  awk -v w=$w '
    NR>2{ww=w++}
    $0!=""{printf "%2s %s\n", ww , $0}
  '
    
por 23.03.2015 / 10:38
0

Eu fiz este script para gerar um calendário de tarefas para as equipes. Ele gera calendário com números de semanas e atribuindo nomes a eles (simplesmente round-robin). Após a impressão ser impressa, basta copiá-lo para o excel e fazer "text to column" por; e mais uma vez executar "texto para coluna" na primeira coluna usando a opção "fixa". O benefício deste calendário (comparando com a orientação horizontal) é que você pode usar o filtro automático (Alt + d f f) e encontrar apenas suas semanas.

#!/usr/bin/ksh
y=2017
set -A team1 Petars Justas Richard Jukka Jesper
set -A team2 Modestas Timo Mats Andreas

i1=0
i2=0
wn=1
own=1

echo "WN     Month        Mo Tu We Th Fr Sa Su ;Team1 ;Team2"
ycal='for m in 1 2 3 4 5 6 7 8 9 10 11 12
do
IFS=
        cal -m $m $y|egrep -v "Mo|^$"|while read line
        do
                echo $line|grep -q $y && mname=$line || print $mname $line|sed 's/'$y'//'
        done
done'
IFS=
echo "$ycal"|while read line2
do
IFS=
        echo "$line2"|grep -v "1  2  3  4  5  6  7"|egrep -q "* 1 |* 1$" || let wn++
        [ $own -ne $wn ] && { \
                [ $i1 -eq ${#team1[@]}-1 ] && i1=0 || let i1++;\
                [ $i2 -eq ${#team2[@]}-1 ] && i2=0 || let i2++; }
        printf '%2s %s ;%s ;%s\n' $wn $line2 ${team1[$i1]} ${team2[$i2]}
        own=$wn
done

Desculpe, codifique um pouco desagradável ... e sem comentários ... mas funciona bem;)

    
por 30.11.2016 / 13:30