Ошибки компоновщика могут произойти, если заголовочный файл и связанная с ним общая библиотека (файл .lib) не синхронизируются. Позволь мне объяснить.
Как работают линкеры? Линкер соответствует объявлению функции (объявленному в заголовке) с его определением (в общей библиотеке) путем сравнения их подписи. Вы можете получить ошибку компоновщика, если компоновщик не найдет определение функции, которое идеально подходит.
Возможно ли получить ошибку компоновщика, даже если объявление и определение, похоже, совпадают? Да! Они могут выглядеть одинаково в исходном коде, но это действительно зависит от того, что видит компилятор. По сути, вы можете столкнуться с такой ситуацией:
// header1.h
typedef int Number;
void foo(Number);
// header2.h
typedef float Number;
void foo(Number); // this only looks the same lexically
Обратите внимание, что хотя обе декларации функций выглядят одинаково в исходном коде, но они действительно различаются в зависимости от компилятора.
Вы можете спросить, как это получается в такой ситуации? Включите пути, конечно! Если при компиляции разделяемой библиотеки путь include приводит к header1.h
, и вы в конечном итоге используете header2.h
в своей собственной программе, вы оставите царапины на своем заголовке, задаваясь вопросом, что произошло (каламбур).
Пример того, как это может произойти в реальном мире, объясняется ниже.
У меня есть два проекта: graphics.lib
и main.exe
. Оба проекта зависят от common_math.h
. Предположим, что библиотека экспортирует следующую функцию:
// graphics.lib
#include "common_math.h"
void draw(vec3 p) { ... } // vec3 comes from common_math.h
И затем вы идете вперед и включаете библиотеку в свой собственный проект.
// main.exe
#include "other/common_math.h"
#include "graphics.h"
int main() {
draw(...);
}
Boom! Вы получаете ошибку компоновщика, и вы понятия не имеете, почему она терпит неудачу. Причина в том, что общая библиотека использует разные версии одного и того же include common_math.h
(я сделал это очевидным здесь в этом примере, включив другой путь, но это может быть не всегда так очевидно. Возможно, путь include отличается в настройки компилятора).
Обратите внимание, что в этом примере компоновщик сказал бы вам, что не смог найти draw()
, когда на самом деле вы знаете, что он явно экспортируется библиотекой. Вы могли часами царапать себе голову, думая, что пошло не так. Дело в том, что компоновщик видит другую подпись, потому что типы параметров немного отличаются. В этом примере vec3
является другим типом в обоих проектах в отношении компилятора. Это может произойти из-за того, что они происходят из двух немного разных файлов include (возможно, включенные файлы поступают из двух разных версий библиотеки).
DUMPBIN - ваш друг, если вы используете Visual Studio. Я уверен, что другие компиляторы имеют другие подобные инструменты.
Процесс выглядит следующим образом:
[1] По проекту я имею в виду набор исходных файлов, которые связаны друг с другом для создания либо библиотеки, либо исполняемого файла .
РЕДАКТИРОВАТЬ 1: Переписать первый раздел, который будет легче понять. Пожалуйста, прокомментируйте ниже, чтобы сообщить мне, нужно ли что-то еще исправлять. Спасибо!
Если вы уверены, что скрипт выполняется за пределами cron, выполните
printf "SHELL=$SHELL\nPATH=$PATH\n* * * * * /bin/bash /var/scripts/vpn-check.sh\n"
Сделайте crontab -e для любого используемого вами crontab и замените его на вывод вышеуказанной команды. Это должно отражать большую часть вашей среды в случае, если есть недостающая проблема или что-то еще. Также проверяйте журналы на наличие ошибок.
Хотя это определенно похоже на то, что сценарий имеет ошибку или вы что-то испортили при копировании его здесь
sed: -e expression #1, char 44: unterminated `s' command
./bad.sh: 5: ./bad.sh: [[: not found
Простой альтернативный скрипт
#!/bin/bash
if [[ $(ping -c3 192.168.17.27) == *"0 received"* ]]; then
/usr/sbin/pppd call home
fi
Ваш скрипт может быть исправлен и упрощен следующим образом:
#!/bin/sh
log=/tmp/vpn-check.log
{ date; ping -c3 192.168.17.27; } > $log
if grep -q '0 received' $log; then
/usr/sbin/pppd call home >>$log 2>&1
fi
. В ходе нашего обсуждения в комментариях мы подтвердили, что сам скрипт работает, но pppd
не работает при работе с cron
, Это связано с тем, что в интерактивной оболочке что-то должно быть иначе, как в окне терминала, и в cron
. Эта проблема очень распространена.
Первое, что нужно сделать, это попытаться вспомнить, какая конфигурация необходима для pppd
. Я не использую его, поэтому не знаю. Может быть, вам нужно установить некоторые переменные среды? В этом случае, скорее всего, вы установите что-то в файле запуска, например .bashrc
, который обычно не используется в неинтерактивной оболочке и объясняет, почему pppd
не работает.
во-вторых, проверить журналы pppd
. Если вы не можете легко найти журналы, загляните в страницу man
, а также файлы конфигурации и попытайтесь найти журналы или как их сделать. На основе журналов вы сможете найти то, что отсутствует при работе в cron
, и решить вашу проблему.
В дополнение к ответам других вы не забыли имя пользователя в своем скрипте crontab?
Попробуйте следующее:
* * * * * root /bin/bash /var/scripts/vpn-check.sh
EDIT
Вот патч вашего кода
#!/bin/sh
/bin/ping -c3 192.168.17.27 > /tmp/pingreport
result=`grep "0 received" /tmp/pingreport`
truncresult=`echo "$result" | /bin/sed 's/^\(.................................\).*$/\1/'`
if [[ $truncresult == "3 packets transmitted, 0 received" ]]; then
/usr/sbin/pppd call home
fi
Наконец, я нашел решение ... Мне нужно запустить cron вместо
crontab -e
, чтобы он работал в
nano /etc/crontab
с чем-то вроде
*/5 * * * * root /bin/bash /var/scripts/vpn-check.sh
и его штраф сейчас!
Спасибо всем за вашу помощь ... надеюсь, что мое решение поможет другим людям.