Mostrar el número de semana en cierto formato usando ncal o cal


16

¿No te encanta cuando dos comandos hacen cada uno lo que quieres pero tampoco los dos?

Esto es lo que calhace. Buen formato. Sin embargo, carece de números semanales:

$ 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              

Esto es lo que ncalhace. Formato extraño, pero con 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   

El tipo de salida que quiero, en realidad un cruce entre caly 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

Respuestas:


13

Si ninguno de estos comandos se ajusta a sus necesidades, puede utilizarlo gcalpara hacer lo que quiera.

Ejemplo

$ 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 el número de semana en la última columna a la derecha.

Referencias


gcal --starting-day=Monday --with-week-numberse ajusta más a mis necesidades pero esta herramienta es excelente.
k0pernikus

9

Esto resalta la fecha de hoy y puede mostrar cualquier mes a través $1del formulario: YYYY-mm-dd... Por defecto es la fecha de hoy

Está configurado para mostrar los números de semana ISO, y el primer día de la semana es el lunes.

#!/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)

Aquí está la pantalla de este mes (con 20resaltado)

       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                

Ni siquiera me di cuenta del problema iso. Eso servirá :)
k0pernikus

1
@ k0pernikus: Acabo de modificar el script ... (unos 35 minutos después de que publicaste el comentario anterior) ... Estaba siendo atrapado 08e 09interpretado como octal en lugar de decimal ... Ahora debería estar bien ...
Peter.O

7

Puede usar nlpara numerar las líneas (ese es el propósito del programa :). Pero necesitas extraer la primera semana del mes de algún lado. Se puede hacer desde ncalsí mismo:

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

Insertamos esto como un parámetro para nlla opción -v(número de línea inicial), y le decimos que solo numere líneas con números o espacios.

$ 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

Sin embargo, todo esto es terriblemente frágil. De todos modos, si no necesita callas opciones más avanzadas, funcionará. Puede ponerlo en un archivo y reemplazarlo "$@"donde lo puse 2 2012.


EDITAR: ¡Pero esto está EQUIVOCADO!¡Acabo de notar que la primera semana de enero puede tener el número 52 o 53! Así que solo tenemos que hacer una excepción para enero, o simplemente extraer todos los números de la semana ncaly aplicarlos a la salida de cal.

Esta es la solución que pensé originalmente, pero pensé (erróneamente) que lo simplificaría usando nl. Utiliza paste, que combina archivos uno al lado del otro. Como no hay ningún archivo, tenemos que usar el bashism <(...); eso es lo que estaba tratando de evitar.

Nuestro primer "archivo" será una lista de los números de la semana, con dos líneas vacías al principio:

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


52
 1
 2
 3
 4
 5

El segundo, solo la salida 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

Mucho más desordenado e incompatible que el otro. En fin ...


No muy bien :-/. Mira mi edición.
angus

7

Genere la secuencia de semanas con ncaly use pastepara tener ambas salidas juntas.

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

Si no le gusta tener pestañas como delimitadores, simplemente agregue algo como sed 's/\t/ /'


Editar : mucho más simple, no hay que preocuparse por las pestañas:

$ paste -d' ' <((echo -n '   '; ncal -w | tail -1 )| fold -w 3) <(cal)

Elegante y encarna muchas de las 17 Reglas Unix de ESR . Debería ser la respuesta aceptada, ya que realmente combina la salida de caly ncal(otros enfoques replican el comportamiento de cualquiera calo ncal).
obispo

4

Una forma de usar Perl (mi idioma de salida del calcomando es español, pero espero que el resultado no varíe del inglés):

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

Salida:

       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

Explicación:

-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.

¿Cómo funcionará esto para los meses siguientes? Las semanas de febrero no comienzan desde el 1 de nuevo, comienzan desde el 5/6 de manera similar, marzo será del 9/10.
Nikhil Mulley

cal 02 2012, ¿tendrá esto un error?
Nikhil Mulley

@Nikhil: No entiendo lo que quieres decir. ¿Puedes tratar de explicarlo más en profundidad? ¿El script falla cal 02 2012? Parecía funcionar en mi prueba.
Birei el

@Nikhil: Ah, está bien. Entendí mal la pregunta. Significa números de semana absolutos y no relativos a cada mes. Eliminaré mi respuesta incorrecta en un momento.
Birei

1
genial ... no elimines la respuesta, guárdala como referencia.
Nikhil Mulley

1

Sin suficiente representante para comentar la respuesta de slm, gcal se puede instalar en Mac OS usandobrew install gcal .

(Encontré la respuesta aquí primero, luego esta respuesta en ask different, pero la respuesta de Unix carecía de toda la información que necesitaba para instalar en la Mac).


0

Aquí está mi solución, que tiene un código más corto y funciona bien para otras fechas que no sean el mes actual. Lo sentimos para los estadounidenses, esto utiliza el formato ISO, es decir, el primer día de la semana es lunes. Esto se hace con la opción -m para cal y la opción% V para fecha

#!/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}
  '

0

Hice este script para generar un calendario de servicio para los equipos. Genera calendario con números de semana y les asigna nombres (simplemente round-robin). Después de imprimir la salida, solo necesita copiarla en Excel y hacer "texto a columna" por; y una vez más realice "texto a columna" en la primera columna usando la opción "fijo". El beneficio de este calendario (en comparación con la orientación horizontal) es que puede usar el filtro automático (Alt + dff) y encontrar solo sus 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
propio = 1

echo "WN Month Mo Tu We Th Fr Sa Su; Team1; Team2"
ycal = `para m en 1 2 3 4 5 6 7 8 9 10 11 12
hacer
IFS =
        cal -m $ m $ y | egrep -v "Mo | ^ $" | mientras lee la línea
        hacer
                echo $ línea | grep -q $ y && mname = $ línea || print $ mname $ line | sed 's /' $ y '//'
        hecho
hecho`
IFS =
echo "$ ycal" | mientras lee line2
hacer
IFS =
        echo "$ line2" | grep -v "1 2 3 4 5 6 7" | egrep -q "* 1 | * 1 $" || dejar wn ++
        [$ own -ne $ wn] && {\
                [$ i1 -eq $ {# team1 [@]} - 1] && i1 = 0 || dejar i1 ++; \
                [$ i2 -eq $ {# team2 [@]} - 1] && i2 = 0 || dejar i2 ++; }
        printf '% 2s% s;% s;% s \ n' $ wn $ line2 $ {team1 [$ i1]} $ {team2 [$ i2]}
        propio = $ wn
hecho

Lo sentimos, el código es un poco desagradable ... y no hay comentarios ... pero funciona bien;)


0

Realmente no quiero instalar gcal, y no pude hacer que funcione correctamente en mi sistema. Entonces, sin gcal, la respuesta de funollet es de hecho la mejor solución. Simplemente lo cambié un poco para que también conserve el formato, como el resaltado del día , los colores , etc., utilizando el comando También eliminé caracteres redundantes, por lo que es adecuado como un alias, como tal:script

alias today="paste -d' ' <((echo ' '{,};ncal -w|tail -1)|fold -w3) <(script /dev/null -qc cal)"

O reemplazar calcon una nueva función. Sin embargo, con esto no puedes hacer cosas como cal -3. Obtiene las semanas correctas pero no están alineadas correctamente. Una solución simple pero no completa es verificar si calse llama sin argumentos, así:

function cal {
    if [[ $# -eq 0 ]]; then
        paste -d' ' <((echo ' '{,};ncal -w $@|tail -1)|fold -w3) <(script /dev/null -qc "cal $@")
    else
        /usr/bin/cal "$@"
    fi
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.