Программа Unix Shell для определения, какая сейчас половина месяца. День месяца (дом) -le 16

Для меня, используя virtualenv, export LD_LIBRARY_PATH=/usr/lib/atlas-base/:${LD_LIBRARY_PATH}в конце моего .bashrcфайла исправил это.

-121 ---32535 ​​-

Проблемы, с которыми я столкнулся, устранены. В одном я не уверен. Другой был результатом моего собственного невежества. Что касается странных ошибок компиляции, которые я испытывал с OpenCV 2 и более простой из двух программ, я не уверен. Однако перекомпиляция OpenCV 2, похоже, решила проблему.

Самая большая ошибка, которую я совершил, была связана с make-файлом. Я не знал, что псевдонимы, определенные в.bashrc, не транслируются в make-файлы и что make-файлы имеют совсем другой синтаксис по сравнению с bash. В bash $(opencv2)вызывает команду, на которую ссылается opencv2, и использует ее вывод в текущей команде. Использование $opencv2будет ссылаться на переменную и возвращать ее значение. В makefile это не так. На самом деле $(opencv2)возвращает значение локально определенной переменной с именем opencv2. Команды могут быть определены этими переменными, но должны быть окружены обратными кавычками/метками. Ниже приведен мой исправленный make-файл:

OPENCV=`pkg-config --cflags --libs opencv2`
segmentation : main.cpp Loader.o MeanShift.o ControlParameters.h defs.h
         g++ -g main.cpp Loader.o MeanShift.o $(OPENCV) -o segmentation      

Loader.o : Loader.cpp Loader.h
         g++ -g -c Loader.cpp $(OPENCV)

MeanShift.o : MeanShift.cpp MeanShift.h
         g++ -g -c MeanShift.cpp $(OPENCV)

clean:
         rm segmentation *.o
0
04.03.2020, 19:11
5 ответов

Резюме

Весь скрипт можно сократить до этих двух строк кода (почти, за исключением экспорта некоторых переменных):

printf -v str '%(yr=%Y mo=%-m dy=%-d)T' -1; eval $str     # bash 4.2+
printf -v fd '%d%02d%02d' "$yr" "$mo" "$((15*(dy/16)+1))"; echo "$fd"

Или (Дата GNU):

str=$(date +'yr=%Y mo=%-m dy=%-d'); eval $str
fd=$(printf '%d%02d%02d' "$yr" "$mo" "$((15*(dy/16)+1))"); echo "$fd"

Детали

Математика для преобразования чисел(dy)в диапазоне 1..31 в 1 или 16 довольно проста:

(dy>=16)*15 + 1

В C результат true имеет значение 1, тогда 1 умножить на 15 равно 15, плюс 1 равно 16. Если dy больше или равно 16. Более короткая математика (немного сложнее для понимания )— сделать простое целочисленное деление:

(dy/16)*15 + 1

Итак, нам нужно только числоdy(дня месяца ). Это можно сделать несколькими способами:

printf '%(%-d)T' -1         # in bash 4.2+:
date +'%-d'                 # in any shell with most date command

Кроме того, значение может быть установлено в переменную с помощью:

printf -v dy '%(%-d)T' -1   # bash (no sub-shell called).
dy=$(date +'%-d')           # at the cost of one sub-shell.

Но поскольку нам нужны также год и месяц, мы можем построить одну строку из одного вызова даты, чтобы установить все переменные и оценить строку:

printf -v str '%(yr=%Y mo=%-m dy=%-d)T'; eval $str

В этом случае eval совершенно безопасен, так как не используется пользовательский ввод, а формат строки четко определен, никаких сюрпризов.

Конечно, эквивалент с датой также возможен, но с дополнительными затратами на одну дополнительную оболочку -для захвата вывода date:

.
str=$(date +'yr=%Y mo=%-m dy=%-d); eval $str

Вам нужна строка:

printf -v fd '%d%02d%02d' "$yr" "$mo" "$((15*(dy/16)+1))"; echo "$fd"

fd=$(printf '%d%02d%02d' "$yr" "$mo" "$((15*(dy/16)+1))"); echo "$fd"

Просто.

-2
28.04.2021, 23:21

Это сработало, и вот мой код, который сработал:

export day=$(date +%d)
export YR=$(date | awk '{print $6}')
export MM=$(date +%m)
echo $DY
echo "$YR$MM$day"

if [[ $day -ge 16 ]]; then
    day=16
else
day=01
fi
printf '%(%Y%m)T%s\n' -1 "$day"



export FD="$YR$MM$day"
echo $FD
0
28.04.2021, 23:21
dd=$(date +%d)
# values 08 and 09 will not work with arithmetic the way you expect
d=${dd#0}         # remove any leading 0
if [ "$d" -ge 16 ] ;then
  half=16
else
  half=01
fi
date "+%Y%m$half"

Я думаю, что этот код легче всего понять. Единственная сложность связана с использованием арифметических выражений оболочки с числами, начинающимися с цифры 0, что вы можете не осознавать, если не сталкивались с этим раньше. Строки формата для dateописаны на справочной странице strftime(3). Обратите внимание, что существуют реализацииdate(или printf), которые не понимают спецификацию преобразования %e. Конструкция ${dd#0}описана в справочной страницеbash(1)(или другой оболочки )в разделе «Расширение параметров».

0
28.04.2021, 23:21

Вы можете использовать приведенный ниже код для достижения вышеуказанного :#коснитесь mycode.sh

#!/bin/bash

export DD=$(date +%d)
export YYYY=$(date | awk '{print $6}')
export MM=$(date +%m)
echo "$YYYY$MM$DD"
if [[ $DD -eq 16 || $DD -eq 01  ]];then

 echo "$DD"

else

 echo " The days are not 1st or 16th "

fi


#sh mycode.sh

О/П

20200303
0
28.04.2021, 23:21

Использование bashверсии 4.2 или выше:

#!/bin/bash

printf -v day '%(%e)T' -1

if [[ $day -lt 16 ]]; then
    # 1st half of the month
    day=01
else
    # 2nd half of the month
    day=16
fi

printf '%(%Y%m)T%s\n' -1 "$day"

Первый printfпечатает текущую дату месяца в виде десятичной цифры в переменную day. Операторы ifограничивают это либо 01, либо 16в зависимости от его значения.

Последнее printfпечатает текущий год и месяц, а затем добавляет в конец строку 01или 16.

Аргумент -1для вызовов printfзаставляет строку формата %(...)Tиспользовать текущее время в качестве метки времени для форматирования (, если вы используете bash4.3 или более позднюю версию, это не является строго обязательным для первого вызова так же неявно ).

Более компактная версия дляbash:

#!/bin/bash

printf -v day '%(%e)T' -1
printf '%(%Y%m)T%.2d\n' -1 "$(( (day < 16) ? 1 : 16 ))"

Здесь я выполняю тест в арифметическом расширении, используя общий тернарный оператор?:. Это приводит к строке 1, если $dayменьше 16, и к 16, если оно больше 16. Результат арифметического расширения затем форматируется в нулевое -заполненное целое число и вставляется после текущего год и месяц.


О вашем коде:

  • Обратите внимание, что [[... ]]требует пробелов вокруг [[и ]](, а ;может стоять сразу после него без пробела, так как это терминатор команды ).
  • Если вы хотите поместить вывод dateили любой команды в переменную, используйте подстановку команд:day=$( date +%e ). Это верно для вашего оператора if, если он должен был выводить значение (, которого нет ).
  • Команды Unix чувствительны к регистру, поэтому ECHO, вероятно, должно быть echo.
  • Формат времени %dвыводит заполненное нулем -целое число между 01и 31. Обратите внимание, что при использовании такого значения в арифметическом контексте (оператор if)будет интерпретировать значения от 01до 07как восьмеричные значения и будет выдавать ошибки для 08. ] и09(это недопустимые восьмеричные числа ). Вот почему я использую %eвместо этого, чтобы получить целые числа, которые не равны нулю -, заполненные между 1и 31.

Об этом последнем пункте :я мог бы также использовать

printf -v day '%(%d)T' -1

, чтобы получить нулевые -заполненные значения между 01и 31, но тогда мне нужно было бы использовать

if [[ 10#$day -ge 16 ]]; then

, чтобы заставить оболочку интерпретировать строку как десятичное целое, а не как восьмеричное целое.


В качестве скрипта /bin/sh(также будет работать с bashверсиями до 4.2, т.е. с оболочкой по умолчанию bashв macOS):

#!/bin/sh

day=$( date +%e )

if [ "$day" -lt 16 ]; then
    # 1st half of the month
    day=01
else
    # 2nd half of the month
    day=16
fi

date +"%Y%m$day"

В стандартной оболочке shнет строки формата %(...)Tвместо bash, поэтому мы вынуждены использовать dateдля форматирования строки даты. Он также использует [... ]для тестов, а не [[... ]](, и переменные должны быть заключены в двойные кавычки внутри ).

Более компактная версия для/bin/sh:

#!/bin/sh

day=$( date +%e )
printf '%s%.2d\n' "$(date +%Y%m)" "$(( (day < 16) ? 1 : 16 ))"

Этот более компактный вариант следует из компактного bashварианта. Единственное отличие состоит в том, что dateиспользуется для форматирования текущего года и месяца.

7
28.04.2021, 23:21

Теги

Похожие вопросы