Як виконати команди бібліотеки з оболонки?


27

Я хотів просто обчислити довжину рядка (тобто хеш-значення). Отже, я відкрив термінал і зробив це:

$ apropos length

що повернуло мене з купою команд / функцій, що мають (3)або (3ssl)додаються в кінці. Тепер людина-людина дає нам інформацію про те, що це section numbersозначає.

3   Library calls (functions within program libraries)

З цікавості я просто спробував усі ці команди (сподіваюся, що хоча б одна спрацює)

strcspn (3)          - get length of a prefix substring
strlen (3)           - calculate the length of a string
strnlen (3)          - determine the length of a fixed-size string
strspn (3)           - get length of a prefix substring
wcslen (3)           - determine the length of a wide-character string
wcsnlen (3)          - determine the length of a fixed-size wide-character string

і не було нічого, крім однієї помилки для кожної команди

$ strnlen HelloWorld 
$ strnlen: command not found

Ну, я знаю , як знайти довжину рядка в оболонці , використовуючи wc -m, expr lengthі інші обхідні шляхи.

Але у мене тут 2 питання:

  1. Як використовувати будь-якуlibrary calls (3) всередині оболонки?
  2. Як обчислити довжину рядка, використовуючи лише виклики бібліотеки, а не інші команди?

ПРИМІТКА. Питання зосереджується на загальному library callsта їх використанні в оболонці. Це робить перше питання важливішим для відповіді.


stackoverflow.com/q/49719554/841108 - це майже дублікат
Basile Starynkevitch

4
В основному, хоча відповідь Майкла є великим злом, відверта відповідь: ви цього не робите. Виклики бібліотеки не пов'язані з оболонкою. Вони використовуються для написання програм на мові С. - Більш загально, читаючи керування, якщо ви не кодуєте програму, просто ігноруйте розділи 2, 3 та 9.
спектри

Off Topic, але OpenVMS має "лексичні" функції, які є інтерфейсами оболонки для багатьох функцій системної бібліотеки.
RonJohn

Відповіді:


39

Ви, мабуть, не повинні цього робити, але можете. Відповідь Кусалананди краще відповідне завдання та пояснює питання. Оскільки ви запитували конкретно, як використовувати будь-які дзвінки з бібліотеки всередині терміналу, ось декілька способів ...


Tiny C Compiler ( tcc) підтримує -runпрапор , який дозволяє вам (в дійсності) витлумачити C код, написавши невелику програму, так що ви можете використовувати бібліотечні виклики всередині терміналу через один виклик цього.

Ви можете запустити strnlenфункцію так:

$ tcc -run <(echo '#include <stdio.h>'; echo '#include <string.h>'; echo 'void main(int argc, char **argv) {printf("%i\n", strnlen(argv[1], 1024));}') "Hello world"
11

Для цього використовується підміна процесу з Bash, zsh та інших оболонок, щоб дати tccфайлу для читання, який, як видається, містить результати всіх echos; є й інші варіанти.

Ви можете створити функцію для створення цього для вас:

call_library_function_s_i() {
    func=$1
    shift
    tcc -run <(echo '#include <stdio.h>'; echo '#include <string.h>'; echo 'void main(int argc, char **argv) {printf("%i\n", '$func'(argv[1]));}') "$*"
}
$ call_library_function_s_i strlen hello world

strlenтут використовував так, що це унарна функція string-> int - вам знадобиться окрема функція для кожного різного типу аритії та повернення).


Іншим варіантом є плагін Bash по Tavis Орманді, який обертає і . Це, мабуть, найближче наближення до того, що ви намагалися. Ви можете використовувати, наприклад:ctypes.shdlopendlsym

$ dlcall -r uint64 strlen "hello world"

і він викличе функцію, як очікувалося.

Це найбільш прямий спосіб зробити це "з терміналу", але навряд чи це буде щось із ваших пакунків для розповсюдження, тому вам доведеться встановлювати його вручну (що нетривіально). Ось кілька інформативних цитат з ctypes.shвласного веб-сайту, щоб створити загальне враження про те, як люди почуваються з цього приводу:

  • "Це огидно"
  • "це має зупинитися"
  • "Ви занадто далеко пішли з цим"

Можуть бути подібні інструменти для інших снарядів, але я не знаю про них. Теоретично немає причин, щоб не могло існувати окрема команда, яка зробила це саме для простих випадків, але я дещо здивований, що не зміг знайти її ...


... так я зробив один! dlcallдозволяє викликати функції бібліотеки з командного рядка :

$ dlcall strnlen "hello world" 6
$ dlcall sin 2.5
$ dlcall strchr "hello world" -c ' '

Він підтримує обмежений набір прототипів функцій, в даний час це не надзвичайно надійно або еластично, але зараз воно існує.


Ви також можете використовувати, наприклад, Python іpython -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world , але це, звичайно, не найпростіший спосіб зробити це. Perl, Ruby та інші мови мають подібні функції.


Тож відповіді на ваші запитання:

  1. Скористайтеся одним із вищезазначених підходів.
  2. Ви дійсно повинні використовувати іншу команду для початкового завантаження вам в бібліотеку, або частина програмного забезпечення , що гачки в вашу оболонку.

Загалом, вам майже напевно буде краще робити це будь-яким іншим способом.


2
"dlcall" нагадує мені (не зовсім однаковий) Windows "rundll": support.microsoft.com/en-gb/help/164787/…
pjc50

1
@ pjc50: Оголошення громадських служб: rundll32 не є інструментом загального призначення для виклику довільних функцій . Його можна використовувати лише для виклику функцій із заданою підписом. Крім того, це не страшенно на майбутнє .
Кевін

29

aproposКоманда корисна в багатьох відносинах, але це дасть вам багато «сміття» теж. Більшість речей, які ви перераховуєте, - це підпрограми бібліотеки С (саме для цього призначено розділ 3 цього посібника), якими ви не можете скористатися безпосередньо з оболонки.

Щоб їх використовувати, вам доведеться написати програму C, яка їх викликає. Це виходить за межі діапазону тем, що охоплюються саме цим сайтом (це було б на темі в StackOverflow ).

Таким чином, це відповіді на ваші запитання:

  1. Ви не можете, це підпрограми бібліотеки С.
  2. Ви не можете, якщо ви не пишете програму C.

Я знаю, ви це знаєте, але задля повноти: в оболонці, якщо у вас є рядок у змінній string, ви можете зробити

string='hello world'
printf 'Length of string "%s" is %d\n' "$string" "${#string}"

Це буде надруковано Length of string "hello world" is 11в терміналі, звідки 11походить, ${#string}який розширюється на довжину рядка в $string.

Внутрішньо оболонка цілком може використовувати один з викликів бібліотеки, який ви перерахували, щоб зробити її обчислення довжини.

Це найефективніший спосіб отримати довжину рядка, який зберігається в змінній оболонки, в оболонці.

Зауважте, що ${#string}це розширення параметра оболонки POSIX , тому він переноситься між усіма оболонками, які вимагають будь-якого ступеня відповідності POSIX.


Частини про функції бібліотеки є хорошим поясненням, але решта цієї відповіді трохи вводить в оману. ОП каже: "Я хотів просто обчислити довжину рядка" Тут не потрібно використовувати printf. Якщо ви хочете роздрукувати його як частину речення, то це може бути найкращим способом. Але відповідь на питання "як мені отримати довжину струни?" це ${#string}частина, а не printf. Ви можете просто, echo ${#string}якщо ви хочете вивести тільки довжину, або призначити її іншій змінній за допомогою string_length=${#string}будь-якої або що завгодно. printf насправді не актуально
Адам,

1
@Adam Я змінив відповідь. Я думаю, що цілком зрозуміло, як отримати довжину рядка, і користувач вже сказав, що знає, як це зробити. При використанні довжини рядка з printfя додати що - то інше , ніж просто сказати «використання ${#string}» (що саме видно з прикладу).
Кусалаланда

15

Я б не робив цього просто strlen(), але це корисна хитрість для випробування коду С іноді.

user @ host: ~ $ gdb gdb
(gdb) старт
Тимчасова точка розриву 1, ... в основному ()
(gdb) print strlen ("foobar")
$ 1 = 6

Ось gdbналагоджувач GNU, і зазвичай для цього буде прийнято назву програми для налагодження. Оскільки у нас його немає, цей приклад дає сам налагодження. Потім startзапускається програма, після чого gdbїї можна використовувати для виконання довільного коду С.


2
Хороший трюк, використовувати gdb. І все ж gdb є частиною інструментів для розробників, і якщо ви хочете використовувати функцію бібліотеки, краще підготуйтеся навчитися користуватися інструментами для розробників.
Дуді Хлопчик

4

Інструмент, який можна використовувати для інтерактивного виклику функцій у спільних бібліотеках: "Колекція компіляторів чаклунства". https://github.com/endrazine/wcc

На сторінці GitHub:

wsh: оболонка чаклунства

Оболонка чаклунства приймає спільні бібліотеки ELF, виконувані файли ELF ET_DYN та скрипти Witchcraft Shell, написані в Punk-C. Він завантажує всі виконувані файли у власний адресний простір та робить їх API доступним для програмування у вбудованому інтерпретаторі. Це забезпечує бінарні функції, подібні до функцій, що надаються через відображення на таких мовах, як Java.

Приклад використання wsh Наступна команда завантажує /usr/sbin/apache2виконуваний файл в wsh, викликає ap_get_server_banner()функцію в апаші для отримання свого банера і відображає його в wshінтерпретаторі.

jonathan@blackbox:~$ wsh /usr/sbin/apache2
> a = ap_get_server_banner()
> print(a)
Apache/2.4.7
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.