Jak wykonać polecenia biblioteki z powłoki?

27

Chciałem po prostu obliczyć długość łańcucha (to jest wartość skrótu). Otworzyłem terminal i zrobiłem to:

$ apropos length

które zwróciło mi zestaw poleceń / funkcji posiadających (3)lub (3ssl)dołączonych na końcu. Teraz człowiek człowiek przekazuje nam informacje o ich section numbersznaczeniu.

3   Library calls (functions within program libraries)

Z ciekawości właśnie wypróbowałem wszystkie te polecenia (mam nadzieję, że przynajmniej jedno zadziała)

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

i otrzymywał tylko ten sam błąd dla każdego polecenia

$ strnlen HelloWorld 
$ strnlen: command not found

Dobrze wiem, jak znaleźć długość ciągu w powłoce użyciu wc -m, expr lengthoraz inne rozwiązania.

Ale mam tutaj 2 pytania:

  1. Jak korzystać z dowolnejlibrary calls (3) powłoki?
  2. Jak obliczyć długość łańcucha przy użyciu samych wywołań biblioteki, a nie innych poleceń?

UWAGA: Pytanie dotyczy ogólnie library callsi ich użycia w powłoce. Dlatego ważniejsze jest udzielenie odpowiedzi na pierwsze pytanie.

C0deDaedalus
źródło
stackoverflow.com/q/49719554/841108 jest prawie duplikatem
Basile Starynkevitch
4
Zasadniczo, chociaż odpowiedź Michaela to świetny hack, prosta odpowiedź brzmi: nie. Wywołania biblioteczne nie są powiązane z powłoką. Służą do pisania programów w języku C. - Mówiąc bardziej ogólnie, podczas czytania stron podręcznika, chyba że
kodujesz
Poza tematem, ale OpenVMS ma funkcje „leksykalne”, które są interfejsami powłoki do wielu funkcji biblioteki systemowej.
RonJohn,

Odpowiedzi:

39

Prawdopodobnie nie powinieneś tego robić, ale możesz. Odpowiedź Kusalanandy jest lepsza dla danego zadania i wyjaśnia problem. Ponieważ pytałam konkretnie jak używać żadnych połączeń biblioteki wewnątrz terminalu, chociaż, oto kilka sposobów ...


Tiny C Compiler ( tcc) obsługuje -runflagę , która pozwala (w efekcie) interpretowania kodu C pisząc mały program, dzięki czemu można korzystać z żadnych połączeń biblioteki wewnątrz terminala za pomocą jednego wywołania tego.

Możesz uruchomić następującą strnlenfunkcję:

$ 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

Używa podstawienia procesów z Bash, zsh i innych powłok, aby dać tccplik do odczytu, który wydaje się zawierać wyniki wszystkich echos; są inne opcje.

Możesz stworzyć funkcję, która wygeneruje to dla Ciebie:

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

(Użyłem strlentutaj, aby była to jednoargumentowa funkcja string-> int - potrzebujesz osobnej funkcji dla każdego innego arity i typu zwracanego).


Inną opcją jest Bash plugin przez Tavis Ormandy, który owija się i . Jest to prawdopodobnie najbliższe przybliżenie do tego, czego próbujesz. Możesz użyć na przykład:ctypes.shdlopendlsym

$ dlcall -r uint64 strlen "hello world"

i wywoła funkcję zgodnie z oczekiwaniami.

Jest to najbardziej bezpośredni sposób na zrobienie tego „z terminala”, ale jest mało prawdopodobne, aby był to pakiet twoich pakietów dystrybucyjnych, więc będziesz musiał zainstalować go ręcznie (co nie jest łatwe). Oto kilka ciekawych cytatów z ctypes.shwłasnej strony internetowej, które dają ogólne wrażenie na temat tego, jak ludzie to robią:

  • "to jest obrzydliwe"
  • „to musi się skończyć”
  • „posunąłeś się za daleko”

Mogą istnieć podobne narzędzia do innych powłok, ale nie wiem o nich. Teoretycznie nie ma powodu, aby nie istniało samodzielne polecenie, które zrobiłoby to dokładnie w prostych przypadkach, ale jestem nieco zaskoczony, że nie udało mi się znaleźć jednego ...


... więc zrobiłem jeden! dlcallpozwala wywoływać funkcje biblioteczne z wiersza poleceń :

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

Obsługuje ograniczony zestaw prototypów funkcji, obecnie nie jest strasznie niezawodny ani odporny, ale teraz istnieje.


Możesz także użyć na przykład Pythona ipython -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world , ale z pewnością nie jest to najłatwiejszy sposób. Perl, Ruby i inne języki mają podobne funkcje, których możesz użyć.


Odpowiedzi na twoje pytania to:

  1. Użyj jednego z powyższych podejść.
  2. Państwo nie trzeba użyć innego polecenia załadowania cię do biblioteki, albo kawałek oprogramowania, które haków do swojej skorupy.

Podsumowując, prawie na pewno lepiej będzie robić to w jakikolwiek inny sposób.

Michael Homer
źródło
2
„dlcall” przypomina mi (nie do końca identyczne) „rundll” systemu Windows: support.microsoft.com/en-gb/help/164787/...
pjc50
1
@ pjc50: Ogłoszenie usługi publicznej: rundll32 nie jest narzędziem ogólnego przeznaczenia do wywoływania dowolnych funkcji . Można go używać tylko do wywoływania funkcji z danym podpisem. Ponadto nie jest zbytnio przyszłościowy .
Kevin,
29

aproposPolecenie jest przydatne na wiele sposobów, ale to nie daje dużo „śmieci” też. Większość rzeczy, które wymieniasz, to procedury biblioteki C (do tego służy sekcja 3 instrukcji), których nie możesz używać bezpośrednio z powłoki.

Aby z nich skorzystać, trzeba napisać program w języku C, który je wywołuje. To wykracza poza zakres tematów omawianych w tej konkretnej witrynie (byłoby na ten temat na StackOverflow ).

Oto zatem odpowiedzi na twoje pytania:

  1. Nie możesz, są to procedury biblioteki C.
  2. Nie możesz, chyba że napiszesz program C.

Wiem, że o tym wiesz, ale ze względu na kompletność: w powłoce, jeśli masz ciąg w zmiennej string, możesz to zrobić

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

Spowoduje to wydrukowanie Length of string "hello world" is 11w terminalu, z którego 11pochodzi, z ${#string}którego rozwija się do długości łańcucha $string.

Wewnętrznie powłoka może z powodzeniem wykorzystywać jedno z wywołań biblioteki, które wymieniono w celu obliczenia długości.

Jest to najbardziej efektywny sposób na uzyskanie długości ciągu przechowywanego w zmiennej powłoki, w powłoce.

Zauważ też, że ${#string}jest to rozszerzenie parametrów powłoki POSIX , dlatego jest przenośne między wszystkimi powłokami, które twierdzą, że są w jakimkolwiek stopniu zgodne z POSIX.

Kusalananda
źródło
Części dotyczące funkcji biblioteki są dobrym wyjaśnieniem, ale reszta tej odpowiedzi jest nieco myląca. OP mówi: „Chciałem po prostu obliczyć długość łańcucha”. Nie ma tu potrzeby używania printf. Jeśli chcesz wydrukować go jako część zdania, może to być najlepszy sposób. Ale odpowiedź na pytanie „jak uzyskać długość łańcucha?” jest ${#string}częścią, a nie printf. Możesz po prostu, echo ${#string}jeśli chcesz wyprowadzić tylko długość lub przypisać ją do innej zmiennej za pomocą string_length=${#string}lub cokolwiek chcesz. printf nie jest tak naprawdę istotny
Adam
1
@Adam Wprowadziłem niewielkie zmiany w odpowiedzi. Myślę, że jest całkiem jasne, jak uzyskać długość łańcucha, a użytkownik już powiedział, że wie, jak to zrobić. Przez stosując długość łańcucha z printfdodam coś innego niż po prostu powiedzieć „użytkowania ${#string}” (co jest oczywiste z przykładu).
Kusalananda
15

Nie zrobiłbym tego po prostu strlen(), ale czasami jest to przydatna sztuczka do wypróbowania kodu C.

użytkownik @ host: ~ $ gdb gdb
(gdb) start
Tymczasowy punkt przerwania 1, ... w main ()
(gdb) print strlen („foobar”)
1 USD = 6

Oto gdbdebuger GNU, który normalnie potrzebowałby nazwy programu do debugowania po nim. Ponieważ go nie mamy, ten przykład sam się debuguje. Następnie starturuchamia program, a następnie gdbmożna go użyć do wykonania dowolnego kodu C.

jpa
źródło
2
Fajna sztuczka, aby użyć gdb. Jednak gdb jest częścią narzędzi programistycznych i jeśli chcesz korzystać z funkcji bibliotecznych, lepiej przygotuj się do nauki korzystania z narzędzi programistycznych.
Dudi Boy,
4

Narzędzie, które można wykorzystać do interaktywnego wywoływania funkcji we współdzielonych bibliotekach: „Witchcraft Compiler Collection”. https://github.com/endrazine/wcc

Ze strony GitHub:

wsh: Skorupa Witchcraft

Powłoka czarów przyjmuje jako dane wejściowe biblioteki współdzielone ELF, pliki wykonywalne ELF ET_DYN i skrypty powłoki Witchcraft napisane w Punk-C. Ładuje wszystkie pliki wykonywalne we własnej przestrzeni adresowej i udostępnia ich API do programowania we wbudowanym interpretera. Zapewnia to funkcje binarne podobne do tych udostępnianych poprzez refleksję na temat języków takich jak Java.

Przykład użycia wsh Poniższe polecenie ładuje /usr/sbin/apache2plik wykonywalny w wsh, wywołuje ap_get_server_banner()funkcję w apache, aby pobrać swój baner i wyświetla go w wshinterpreter.

jonathan@blackbox:~$ wsh /usr/sbin/apache2
> a = ap_get_server_banner()
> print(a)
Apache/2.4.7
Alex D.
źródło