#bash #bc #libreadline
#bash #bc #libreadline
Вопрос:
Я подключаюсь ssh
к другой машине для выполнения скрипта bash, проблемная часть которого заключается в следующем:
fkeypar "ex1.fef[1]" TSTARTI #### fkeypar is an external command to get some values to assign to the subsequent variables
t0i="$(expr $(pget fkeypar value) - 11544)"
fkeypar "ex1lc.fits[2]" TELAPSE
lengthini=`pget fkeypar value`
fkeypar "ex7lc.fits[2]" TSTOP
lengthfin=`pget fkeypar value`
fkeypar "ex1lc.fits[2]" TSTART
ijd=`pget fkeypar value`
i=$(echo "($ijd - $t0i) / $period 1" | bc -l | sed 's/..*//')
ifin=$(echo "($lengthfin - $ijd)/$period 1" | bc -l | sed 's/..*//')
echo "($ijd - $t0i) / $period 1" | bc
for ((n=$i; n<=$ifin; n ))
do
...
Это возвращает следующие ошибки:
bc: symbol lookup error: /science/heasoft-6.14/x86_64-unknown-linux-gnu-libc2.9/lib/libreadline.so.6: undefined symbol: PC
bc: symbol lookup error: /science/heasoft-6.14/x86_64-unknown-linux-gnu-libc2.9/lib/libreadline.so.6: undefined symbol: PC
bc: symbol lookup error: /science/heasoft-6.14/x86_64-unknown-linux-gnu-libc2.9/lib/libreadline.so.6: undefined symbol: PC
./script: line 39: ((: n=: syntax error: operand expected (error token is "=")
МНОГО погуглив, я обнаружил, что я очень связан с этими «ошибками»:
https://science.nrao.edu/forums/viewtopic.php?f=44amp;t=75
https://bugzilla.redhat.com/show_bug.cgi?id=162023
https://dba.stackexchange.com/questions/31143/libreadline-so-6
Я понятия не имею, как это исправить, не пробуя случайные вещи. Любая помощь действительно ценится.
РЕДАКТИРОВАТЬ: я забыл упомянуть, что во многих моих испытаниях, много раз используя ssh, мне каким-то образом удалось не получить ошибку и запустить скрипт с тем же синтаксисом, что и в вопросе. В тот момент я подумал, что это проблема с синтаксисом, но затем ошибка снова появилась при последующих ssh-вводах.
ПРАВКА2: не имеет значения, какую версию heasoft
я загружаю, ошибка всегда появляется для heasoft-6.14
версии. Я думаю, что это связано с возможным исправлением.
Комментарии:
1. Это вообще не относится к сценарию — это проблема с копией bc на этом конкретном компьютере. Обратитесь за помощью к своему системному администратору; мы не можем помочь вам в этом.
2. @CharlesDuffy, я понимаю. Что значит «Попросить вашего системного администратора помочь»? Это файл или человек?
3. Ваш системный администратор — человек.
Ответ №1:
По большей части это проблема, с которой мы не можем помочь — кто-то с правами администратора на перекомпиляцию bc
(или, лучше, кто-то, кто знает, почему вы не делаете разумные вещи и используете версию, предоставленную поставщиком ОС), должен был бы это исправить. (Это может быть так же просто, как переименовать bc
under /science/heasoft-6.14
из пути и разрешить вместо него использовать реализацию, предоставляемую поставщиком в ПУТИ).
Тем не менее, если вы выполняете только целочисленную математику, у этого скрипта вообще нет причин использовать bc:
i=$(( (idj - t01) / period 1 ))
ifin=$(( ( lengthfin - ijd ) / period 1 ))
echo "$(( ( ijd - t01 ) / period 1 ))"
Ошибка, которую вы имеете в строке 39, является следствием этих ошибок в bc
— скрипт ожидает i
, что он будет содержать число, но это пустая строка, поэтому n=$i
не может быть вычислен "$i"
как число, поэтому он завершается с ошибкой. В математическом контексте (который создает двойная скобка) i
вычисляется как 0, если переменная не определена, но $i
вызывает ошибку в том же сценарии; какой из них использовать, зависит от вашего желаемого поведения. Если вы хотите, чтобы при неопределенной переменной возникала ошибка, используйте $varname
inside of (( ))
; если вы хотите, чтобы сценарий продолжался со значением 0, используйте bare varname
.
Комментарии:
1. Вы имели в виду
i=$(( ($idj - $t0i) / $period 1 ))
?2. Нет, я этого не делал. Оператор расширения является необязательным внутри математического контекста; Я подробно объясняю это в своем ответе.
3. Я вижу, редактирование появилось позже. Однако я забыл упомянуть, что во многих моих испытаниях, много раз используя ssh, мне каким-то образом удалось не получить ошибку и запустить скрипт с тем же синтаксисом, что и в вопросе. В тот момент я подумал, что это проблема с синтаксисом, но затем ошибка снова появилась при последующих ssh-вводах.
4. … в этом случае я предполагаю, что в используемой вами системе есть некоторые настройки среды, такие как
LD_LIBRARY_PATH
… которые описывают проблему, и что вам иногда удавалось добиться того, чтобы избежать их настройки. (Также может быть, что в некоторых случаях использования у вас нетPATH
указания на использование этой цепочки инструментов, отличной от стандартной; не имея доступа к системе, мы можем только строить предположения, и в любом случае это не проблема программирования). Тем не менее, это вопрос к людям, которые настраивают и поддерживают систему, а не к сообществу StackOverflow.
Ответ №2:
Я понятия не имею, как это исправить, не пробуя случайные вещи. Любая помощь действительно ценится.
Рецепт создания Readline на вашей платформе нарушен. Вот технические подробности… В общем объекте отсутствуют символы, что вроде нормально:
$ ldd -r -d /usr/local/lib/libreadline.so
linux-vdso.so.1 (0x00007ffea672a000)
libc.so.6 => /lib64/libc.so.6 (0x00007fec922eb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fec92521000)
undefined symbol: UP (/usr/local/lib/libreadline.so)
undefined symbol: PC (/usr/local/lib/libreadline.so)
undefined symbol: BC (/usr/local/lib/libreadline.so)
undefined symbol: tputs (/usr/local/lib/libreadline.so)
undefined symbol: tgoto (/usr/local/lib/libreadline.so)
undefined symbol: tgetflag (/usr/local/lib/libreadline.so)
undefined symbol: tgetent (/usr/local/lib/libreadline.so)
undefined symbol: tgetnum (/usr/local/lib/libreadline.so)
undefined symbol: tgetstr (/usr/local/lib/libreadline.so)
На самом деле, я думаю, что сборка должна завершиться неудачно из-за отсутствия символов. Но сопровождающий думает иначе и предпочитает распространять свою боль и страдания на пользователей своей библиотеки.
Отсутствующие символы являются частью Ncurses и Terminfo, но библиотека ссылок отсутствует. Это не нормально. Библиотека ссылок должна быть чем-то вроде libtinfo.so
или libtinfow.so
, но она отсутствует:
$ ldd /usr/local/lib/libreadline.so
linux-vdso.so.1 (0x00007ffd535cb000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3a5183c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3a520b5000)
И вот где UP
PC
и находятся друзья:
$ nm -D /usr/local/lib/libtinfow.so | grep -E 'UP|PC'
000000000023797e B PC
0000000000237968 B UP
Предполагается, что вы можете добавить -ltinfo
или -ltinfow
в свой LIBS
/ LDLIBS
во время настройки строки чтения, но это не работает. Добавление -ltinfo
или -ltinfow
игнорируется.
Исправление на практике заключается в исправлении makefile строки чтения, а затем создании Ncurses и Readline из исходных текстов.
Вот как выглядит исправление Readline. Исправление было создано с помощью diff -u
:
--- shlib/Makefile.in
shlib/Makefile.in
@@ -174,11 174,11 @@
$(SHARED_READLINE): $(SHARED_OBJ)
$(RM) $@
- $(SHOBJ_LD) ${SHOBJ_LDFLAGS} ${SHLIB_XLDFLAGS} -o $@ $(SHARED_OBJ) $(SHLIB_LIBS)
$(SHOBJ_LD) ${SHOBJ_LDFLAGS} ${SHLIB_XLDFLAGS} -o $@ $(SHARED_OBJ) $(SHLIB_LIBS) -ltinfo
$(SHARED_HISTORY): $(SHARED_HISTOBJ) xmalloc.so xfree.so
$(RM) $@
- $(SHOBJ_LD) ${SHOBJ_LDFLAGS} ${SHLIB_XLDFLAGS} -o $@ $(SHARED_HISTOBJ) xmalloc.so xfree.so $(SHLIB_LIBS)
$(SHOBJ_LD) ${SHOBJ_LDFLAGS} ${SHLIB_XLDFLAGS} -o $@ $(SHARED_HISTOBJ) xmalloc.so xfree.so $(SHLIB_LIBS) -ltinfo
# Since tilde.c is shared between readline and bash, make sure we compile
# it with the right flags when it's built as part of readline
Как только вы исправите makefile и создадите Ncurses и Readline, ваши библиотеки ссылок будут включать libtinfo.so
. Дерьмо больше не будет нарушаться. libtinfo.so
Ссылка на уведомление приведена ниже.
$ ldd /usr/local/lib/libreadline.so
linux-vdso.so.1 (0x00007ffd535cb000)
libtinfow.so.6 => /usr/local/lib/libtinfow.so.6 (0x00007f3a51c2d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3a5183c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3a520b5000)
Теперь может быть сложно правильно настроить Ncurses . Это потому, что существует неширокая и широкая версия всех библиотек. В Ncurses их примерно 6:
$ ls /usr/local/lib/lib*w.so*
/usr/local/lib/libformw.so /usr/local/lib/libncursesw.so.6
/usr/local/lib/libformw.so.6 /usr/local/lib/libncurses w.so.6.1
/usr/local/lib/libformw.so.6.1 /usr/local/lib/libncursesw.so.6.1
/usr/local/lib/libmenuw.so /usr/local/lib/libpanelw.so
/usr/local/lib/libmenuw.so.6 /usr/local/lib/libpanelw.so.6
/usr/local/lib/libmenuw.so.6.1 /usr/local/lib/libpanelw.so.6.1
/usr/local/lib/libncurses w.so /usr/local/lib/libtinfow.so
/usr/local/lib/libncursesw.so /usr/local/lib/libtinfow.so.6
/usr/local/lib/libncurses w.so.6 /usr/local/lib/libtinfow.so.6.1
Я создаю широкие версии Ncurses с помощью опции configure --enable-widec
. --enable-widec
описывается как:
Этот переключатель приводит к созданию библиотек с широкими символами (например, libncursesw.so.6.2) вместо обычных (например, libncurses.so.6.2). Эти библиотеки с широкими символами можно использовать как в многобайтовых, так и в традиционных 8-разрядных языках, в то время как обычные библиотеки работают должным образом только в 8-разрядных языках. Широкосимвольные и обычные библиотеки совместимы с исходным кодом, но не совместимы с двоичным кодом.
Если вы настраиваете Ncurses с --enable-widec
помощью, то вы используете libtinfow.so
в качестве библиотеки ссылок для Readline . Если вы используете неширокую версию, то вы используете libtinfo.so
в качестве библиотеки ссылок для Readline .
Если вы настраиваете Ncurses с --enable-widec
помощью , тогда вы должны настроить свою широкую строку чтения с --enable-multibyte
помощью . Если вы создаете Bash из исходных текстов и используете свою широкую строку чтения, вам следует настроить Bash с --enable-multibyte
помощью . Вы должны обратить внимание на детали…
И нет, разные флаги для одного и того же параметра — --enable-widec
и --enable-multibyte
— верны. Зачем быть последовательным, когда вы можете добавить путаницы?
Вы можете поблагодарить парня, который поддерживает Ncurses и Readline за этот беспорядок. Он не следует стандартным рабочим процессам GNU или рекомендациям Linux. Я презираю работу с дерьмом, которое он поддерживает. Вы потратите часы, пытаясь выяснить, как сделать что-то, что должно быть простым, например, какие параметры использовать, или заставить Readline использовать правильную библиотеку ссылок, или получить зависимость, такую как BC или OpenLDAP, для правильной сборки.
Еще одна проблема — утечки памяти. Если вам не повезло с этим на Android, вы можете рассчитывать на исчерпание ресурсов, потому что библиотеки пропускают так много памяти. Android через JNI будет загружать и выгружать общие объекты тысячи раз, и вам не хватит памяти из-за накопленных утечек памяти.
Наконец, нет публичного репозитория для Ncurses и Readline . Невозможно сделать запрос на извлечение или предложить исправления для его источников. Его идея a git pull
— это дерьмо: применение исправлений.