Отображение номера недели в определенном формате с использованием ncal или cal

16

Разве вам не нравится, когда две команды выполняют одну вещь, которую вы хотите, но ни одна не делает обе?

Это то, что calделает. Хорошее форматирование. Не хватает номера недели, хотя:

$ 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              

Это то, что ncalделает. Странное форматирование, но с номерами недель:

$ 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   

Тип вывода, который я хочу, на самом деле скрещивание между calи 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
k0pernikus
источник

Ответы:

13

Если ни одна из этих команд не соответствует вашим потребностям, вы можете использовать gcalвместо этого то, что хотите.

пример

$ 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

Печатает номер недели в последнем столбце справа.

Ссылки

SLM
источник
gcal --starting-day=Monday --with-week-numberбольше соответствует моим потребностям, но этот инструмент великолепен.
k0pernikus
9

Это выделяет сегодняшнюю дату и может отображать любой месяц с помощью $1формы: YYYY-mm-dd... По умолчанию используется сегодняшняя дата.

Он настроен так, чтобы показывать номера недель по ISO, а первый день недели - понедельник.

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

Вот показ этого месяца (с 20выделенным)

       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                
Peter.O
источник
Я даже не заметил изо-проблемы. Это будет делать :)
k0pernikus
1
@ k0pernikus: Я только что изменил сценарий .. (примерно через 35 минут после того, как вы опубликовали вышеупомянутый комментарий) .. Он был пойман 08и 09интерпретировался как восьмеричное, а не десятичное . Теперь все должно быть хорошо ...
Peter.O
7

Вы можете использовать nlдля нумерации строк (это цель программы :). Но вам нужно извлечь первую неделю месяца откуда-то. Это можно сделать из ncalсебя:

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

Мы вставляем это как параметр в параметр nl's -v(начальный номер строки) и сообщаем его только числовым строкам с номерами или пробелами.

$ 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

Это все очень хрупкий, хотя. В любом случае, если вам не нужны calболее продвинутые опции, это сработает. Вы можете положить его в файл и заменить, "$@"где я положил 2 2012.


РЕДАКТИРОВАТЬ: Но это НЕПРАВИЛЬНО! Я только заметил, что первая неделя января может иметь номер 52 или 53! Таким образом, мы просто должны сделать исключение для января или просто извлечь все номера недель из ncalи применить их к выходным данным cal.

Это решение, которое я думал первоначально, но я думал (ошибочно), что упростил бы его использование nl. Он использует paste, который объединяет файлы бок о бок. Поскольку файла нет, мы должны использовать bashism <(...); это то, чего я пытался избежать.

Наш первый «файл» будет список номеров недели, с двумя пустыми строками в начале:

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


52
 1
 2
 3
 4
 5

Второй, просто вывод cal. Все вместе, как параметры для 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

Гораздо более грязный и несовместимый, чем другой. Эн фин ...

ангус
источник
Не так здорово: - /. Смотрите мое редактирование.
ангус
7

Создайте последовательность недель с помощью ncalи используйте pasteдля получения обоих выходов рядом.

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

Если вам не нравятся вкладки в качестве разделителей, просто добавьте что-то вроде sed 's/\t/ /'


Изменить : гораздо проще, не нужно заботиться о вкладках:

$ paste -d' ' <((echo -n '   '; ncal -w | tail -1 )| fold -w 3) <(cal)
funollet
источник
Элегантный и воплощает многие из 17 правил Unix ESR . Должен быть принятый ответ, так как он действительно сочетает в себе выходные данные calи ncal(другие подходы повторяют поведение либо calили ncal).
епископ
4

Один из способов использования Perl (мой выходной язык cal команды - испанский, но я надеюсь, что результат не отличается от английского):

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

Выход:

       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

Объяснение:

-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.
Birei
источник
как это будет работать в последующие месяцы. Февральские недели не начинаются с 1, они начинаются с 5/6, аналогично, март будет с 9/10.
Нихил Малли
Cal 02 2012, будет ли это не удалось ??
Nikhil Mulley
@Nikhil: я не понимаю, что ты имеешь в виду. Можете ли вы попытаться объяснить это более подробно? Сценарий не работает с cal 02 2012? Казалось, сработало в моем тесте.
Бирей
@Nikhil: Ах, хорошо. Я неправильно понял вопрос. Это означает абсолютные номера недели, а не относительно каждого месяца. Я удалю свой неправильный ответ через некоторое время.
Бирей
1
круто .. не удаляйте ответ, пожалуйста, сохраните его для справки.
Nikhil Mulley
1

Без достаточного количества представителей, чтобы прокомментировать ответ с помощью slm , gcal можно установить на Mac OS с помощью brew install gcal.

(Сначала я нашел ответ здесь, затем этот ответ на другой вопрос, но в ответе unix не было всей информации, необходимой для установки на Mac.)

user3.1415927
источник
0

Вот мое решение, которое короче в коде и отлично работает для других дат, чем текущий месяц. Извините за жителей США, здесь используется формат ISO, т.е. 1-й день недели - понедельник. Это делается с помощью опции -m для cal и опции% V для даты

#!/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}
  '
Gunstick
источник
0

Я сделал этот скрипт для генерации дежурного календаря для команд. Он генерирует календарь с номерами недель и назначением им имен (просто циклический перебор). После того, как вывод напечатан, вам просто нужно скопировать его в Excel и сделать «текст в столбец»; и еще раз выполнить «текст в столбец» в первом столбце, используя опцию «исправлено». Преимущество этого календаря (по сравнению с горизонтальной ориентацией) заключается в том, что вы можете использовать автофильтр (Alt + dff) и находить только свои недели.

#! / USR / бен / КШ
у = 2017
set -A team1 Петар Юстас Ричард Юкка Джеспер
set -A team2 Модестас Тимо Матс Андреас

i1 = 0
i2 = 0
Wn = 1
собственный = 1

echo "WN Month Mo Tu We Thr Sa Su; Team1; Team2"
ycal = `для м в 1 2 3 4 5 6 7 8 9 10 11 12
делать
IFS =
        cal -m $ m $ y | egrep -v "Mo | ^ $" | во время чтения строки
        делать
                echo $ line | grep -q $ y && mname = $ line || выведите $ mname $ line | sed 's /' $ y '//'
        сделано
done`
IFS =
echo "$ ycal" | пока читается line2
делать
IFS =
        echo "$ line2" | grep -v "1 2 3 4 5 6 7" | egrep -q "* 1 | * 1 $" || пусть wn ++
        [$ own -ne $ wn] && {\
                [$ i1 -eq $ {# team1 [@]} - 1] && i1 = 0 || пусть i1 ++; \
                [$ i2 -eq $ {# team2 [@]} - 1] && i2 = 0 || пусть i2 ++; }
        printf '% 2s% s;% s;% s \ n' $ wn $ line2 $ {team1 [$ i1]} $ {team2 [$ i2]}
        собственные = $ шп
сделано

Извините, код немного неприятный ... и без комментариев ... но он работает хорошо;)

Петрас Л
источник
0

Я действительно не хочу устанавливать gcal, и я не мог заставить его работать должным образом в моей системе. Так что без gcal ответ funollet - действительно лучшее решение. Я чуть-чуть изменил его, чтобы он также сохранял форматирование, такое как дневная подсветка , цвета и т. Д., С помощью scriptкоманды. Я также удалил лишние символы, что делает его пригодным для использования в качестве псевдонима:

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

Или заменить calна новую функцию. Тем не менее, с этим вы не можете делать такие вещи, как cal -3. Вы получаете правильные недели, но они не выровнены должным образом. Простое, но не полное решение - проверить, calвызывается ли без аргументов, например:

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
}
fivethous
источник