it-swarm.com.de

Wie führe ich Bibliotheksbefehle aus der Shell aus?

Ich wollte einfach die Länge eines Strings berechnen (das ist ein Hashwert). Also öffnete ich das Terminal und tat dies:

$ apropos length

das gab mir eine Reihe von Befehlen/Funktionen zurück, an deren Ende (3) oder (3ssl) angehängt war. Jetzt man man gibt uns Auskunft darüber, was diese section numbers Bedeuten.

3   Library calls (functions within program libraries)

Aus Neugier habe ich es einfach mit all diesen Befehlen versucht (in der Hoffnung, dass mindestens einer funktionieren würde)

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

und bekam nur den gleichen Fehler für jeden Befehl

$ strnlen HelloWorld 
$ strnlen: command not found

Nun, ich weiß wie man die Länge eines Strings in Shell findet mit wc -m, expr length und andere Problemumgehungen.

Aber ich habe hier zwei Fragen:

  1. Wie verwende ich ein beliebiges library calls (3) in der Shell?
  2. Wie berechnet man die Stringlänge nur mit Bibliotheksaufrufen und nicht mit anderen Befehlen?

HINWEIS: Die Frage konzentriert sich im Allgemeinen auf library calls Und deren Verwendung in der Shell. Das macht die Beantwortung der ersten Frage wichtiger.

27
C0deDaedalus

Sie wahrscheinlich sollten nicht tun, aber Sie können. Kusalanandas Antwort ist besser für die anstehende Aufgabe und erklärt das Problem. Da Sie speziell gefragt haben, wie any Bibliotheksaufrufe im Terminal verwendet werden sollen, gibt es hier einige Möglichkeiten ...


Der Tiny C Compiler (tcc) unterstützt ein -run - Flag , mit dem Sie (praktisch) C-Code interpretieren können, indem Sie ein kleines Programm schreiben, sodass Sie kann alle Bibliotheksaufrufe innerhalb des Terminals durch einen einzigen Aufruf verwenden.

Sie können die Funktion strnlen folgendermaßen ausführen:

$ 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

Dies verwendet Prozessersetzung aus Bash, zsh und anderen Shells, um tcc eine zu lesende Datei zu geben, die die Ergebnisse aller echos zu enthalten scheint; Es gibt andere Möglichkeiten.

Sie könnten eine Funktion erstellen, um dies für Sie zu generieren:

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

(Ich habe hier strlen verwendet, damit es sich um eine unäre Funktionszeichenfolge handelt-> int - Sie benötigen für jede Arität und jeden Rückgabetyp eine separate Funktion.).


Eine andere Option ist das ctypes.sh Bash-Plugin von Tavis Ormandy, das dlopen und dlsym zusammenfasst. Dies ist wahrscheinlich die nächste Annäherung an das, was Sie versucht haben. Sie können zum Beispiel verwenden:

$ dlcall -r uint64 strlen "hello world"

und es wird die Funktion wie erwartet aufrufen.

Dies ist der direkteste Weg, dies "vom Terminal aus" zu tun, aber es ist unwahrscheinlich, dass Ihre Distributionspakete etwas enthalten, sodass Sie es manuell installieren müssen (was nicht trivial ist). Hier sind einige informative Zitate von ctypes.sh 'S eigener Website , um einen allgemeinen Eindruck davon zu vermitteln, wie sich die Leute dabei fühlen:

  • "das ist wiederlich"
  • "das muss aufhören"
  • "Du bist damit zu weit gegangen"

Es gibt vielleicht ähnliche Werkzeuge für andere Muscheln, aber ich weiß nichts darüber. Theoretisch gibt es keinen Grund, warum es keinen eigenständigen Befehl geben könnte, der dies genau für die einfachen Fälle tut, aber ich bin etwas überrascht, dass ich keinen gefunden habe ...


... also habe ich eine gemacht! dlcall lässt Sie Bibliotheksfunktionen über die Befehlszeile aufrufen :

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

Es unterstützt eine begrenzte Anzahl von Funktionsprototypen, ist derzeit nicht besonders zuverlässig oder belastbar, existiert aber jetzt.


Sie könnten zum Beispiel auch Python und python -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world verwenden, aber es ist sicherlich nicht der einfachste Weg, dies zu tun. Perl, Ruby und andere Sprachen verfügen über ähnliche Funktionen, die Sie verwenden können.


Die Antworten auf Ihre Fragen lauten also:

  1. Verwenden Sie einen der oben genannten Ansätze.
  2. Sie do müssen einen anderen Befehl verwenden, um bootstrap Sie in die Bibliothek oder eine Software, die sich in Ihre Shell einhakt).

Alles in allem sind Sie mit ziemlicher Sicherheit besser dran, wenn Sie dies anders machen.

39
Michael Homer

Der Befehl apropos ist in vielerlei Hinsicht nützlich, gibt Ihnen aber auch viel "Junk". Die meisten Dinge, die Sie auflisten, sind C-Bibliotheksroutinen (dafür ist Abschnitt 3 des Handbuchs vorgesehen), die Sie nicht direkt über die Shell verwenden können.

Um sie zu verwenden, müssten Sie ein C-Programm schreiben, das sie aufruft. Dies liegt außerhalb des Themenbereichs, der von dieser bestimmten Site behandelt wird (es würde sich um ein Thema unter StackOverflow handeln).

Dies sind also die Antworten auf Ihre Fragen:

  1. Sie können nicht, es sind C-Bibliotheksroutinen.
  2. Sie können nicht, es sei denn, Sie schreiben ein C-Programm.

Ich weiß, dass Sie das wissen, aber der Vollständigkeit halber: Wenn Sie in der Shell eine Zeichenfolge in einer Variablen string haben, können Sie dies tun

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

Dies gibt Length of string "hello world" is 11 In dem Terminal aus, in dem 11 Von ${#string} Stammt, das sich auf die Länge der Zeichenfolge in $string Erweitert.

Intern verwendet die Shell möglicherweise einen der von Ihnen aufgelisteten Bibliotheksaufrufe, um die Längenberechnung durchzuführen.

Dies ist der effizienteste Weg, um die Länge einer Zeichenfolge zu ermitteln, die in einer Shell-Variablen in der Shell gespeichert ist.

Beachten Sie auch, dass ${#string}eine POSIX-Shell-Parametererweiterung ist und daher zwischen allen Shells portierbar ist, die einen beliebigen Grad an POSIX-Konformität beanspruchen.

28
Kusalananda

Ich würde dies nicht nur für strlen() tun, aber es ist manchmal ein nützlicher Trick, um C-Code auszuprobieren.

 user @ Host: ~ $ gdb gdb 
 (gdb) start 
 Temporärer Haltepunkt 1, ... in main () 
 (gdb) print strlen (" foobar ") 
 $ 1 = 6 

Hier ist gdb der Debugger GNU, und es würde normalerweise einen Programmnamen benötigen, um danach zu debuggen. Da wir keinen haben, gibt es dieses Beispiel selbst zum Debuggen. Dann start startet das Programm und danach kann gdb verwendet werden, um beliebigen C-Code auszuführen.

15
jpa

Ein Tool, mit dem Funktionen in gemeinsam genutzten Bibliotheken interaktiv aufgerufen werden können: die "Witchcraft Compiler Collection". https://github.com/endrazine/wcc

Von der GitHub-Seite:

wsh: Die Hexenhülle

Die Hexen-Shell akzeptiert gemeinsam genutzte ELF-Bibliotheken, ausführbare ELF ET_DYN-Dateien und in Punk-C geschriebene Hexen-Shell-Skripte als Eingabe. Es lädt alle ausführbaren Dateien in seinen eigenen Adressraum und stellt ihre API für die Programmierung in seinem eingebetteten Interpreter zur Verfügung. Dies bietet Binärfunktionen, die denen ähneln, die durch Reflektion in Sprachen wie Java bereitgestellt werden.

Beispiel für die Verwendung von wsh Der folgende Befehl lädt die ausführbare Datei /usr/sbin/Apache2 In wsh und ruft die Funktion ap_get_server_banner() in Apache auf Rufen Sie das Banner ab und zeigen Sie es im Interpreter wsh an.

[email protected]:~$ wsh /usr/sbin/Apache2
> a = ap_get_server_banner()
> print(a)
Apache/2.4.7
4
Alex D