неопределенный символ libreadline: ПК в bash при использовании | bc -l

#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 — это дерьмо: применение исправлений.