web-dev-qa-db-fra.com

Comment exécuter des commandes de bibliothèque à partir du shell?

Je voulais simplement calculer la longueur d'une chaîne (c'est-à-dire la valeur de hachage). J'ai donc ouvert le terminal et j'ai fait ceci:

$ apropos length

qui m'a renvoyé un tas de commandes/fonctions ayant (3) ou (3ssl) ajouté à la fin d'entre eux. Maintenant man man nous donne des informations sur ce que ces section numbers Signifient.

3   Library calls (functions within program libraries)

Par curiosité, j'ai juste essayé avec toutes ces commandes (en espérant qu'au moins une fonctionnerait)

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

et n'a obtenu que la même erreur pour chaque commande

$ strnlen HelloWorld 
$ strnlen: command not found

Eh bien, je sais comment trouver la longueur d'une chaîne dans Shell en utilisant wc -m, expr length et d'autres solutions.

Mais, j'ai 2 questions ici:

  1. Comment utiliser toute library calls (3) à l'intérieur du shell?
  2. Comment calculer la longueur d'une chaîne en utilisant uniquement des appels de bibliothèque et non d'autres commandes?

REMARQUE: la question se concentre en général sur library calls Et leur utilisation dans le shell. Cela rend la première question plus importante à répondre.

27
C0deDaedalus

Vous probablement ne devriez pas faire cela, mais vous pouvez. réponse de Kusalananda est mieux pour la tâche à accomplir et explique le problème. Puisque vous avez demandé spécifiquement comment utiliser les appels à la bibliothèque any à l'intérieur du terminal, voici quelques façons ...


Le Tiny C Compiler (tcc) prend en charge un indicateur -run qui vous permet (en effet) d'interpréter le code C en écrivant un petit programme, donc vous peut utiliser tous les appels de bibliothèque à l'intérieur du terminal via une seule invocation de cela.

Vous pouvez exécuter la fonction strnlen comme ceci:

$ 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

Cela utilise substitution de processus de Bash, zsh et d'autres shells pour donner à tcc un fichier à lire qui semble contenir les résultats de tous les echos; il existe d'autres options.

Vous pouvez créer une fonction pour générer ceci pour vous:

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

(J'ai utilisé strlen ici pour que ce soit une chaîne de fonction unaire -> int - vous auriez besoin d'une fonction distincte pour chaque arité et type de retour différents).


Une autre option est le plugin ctypes.sh Bash par Tavis Ormandy, qui regroupe dlopen et dlsym. C'est probablement l'approximation la plus proche de ce que vous essayiez. Vous pouvez utiliser, par exemple:

$ dlcall -r uint64 strlen "hello world"

et il appellera la fonction comme prévu.

C'est le moyen le plus direct de le faire "à partir du terminal", mais il est peu probable que vos packages de distribution soient installés, vous devrez donc l'installer manuellement (ce qui n'est pas trivial). Voici quelques informations citations du propre site Web de ctypes.sh pour donner une impression générale de la façon dont les gens se sentent à ce sujet:

  • "c'est dégoutant"
  • "cela doit s'arrêter"
  • "tu es allé trop loin avec ça"

Il peut y avoir des outils similaires pour d'autres obus, mais je ne les connais pas. En théorie, il n'y a aucune raison qu'il ne puisse pas y avoir de commande autonome qui fasse exactement cela pour les cas simples, mais je suis quelque peu surpris de ne pas en avoir trouvé un ...


... alors j'en ai créé un! dlcall vous permet d'appeler les fonctions de la bibliothèque à partir de la ligne de commande :

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

Il prend en charge un ensemble limité de prototypes de fonctions, il n'est pas terriblement fiable ou résilient actuellement, mais il existe maintenant.


Vous pouvez également utiliser, par exemple, Python et python -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world , mais ce n'est certainement pas la manière la plus simple de s'y prendre. Perl, Ruby et d'autres langages ont des fonctionnalités similaires que vous pourriez utiliser.


Les réponses à vos questions sont donc:

  1. Utilisez l'une des approches ci-dessus.
  2. Vous faites devez utiliser une autre commande pour bootstrap vous dans la bibliothèque, ou un logiciel qui se connecte à votre Shell.

Dans l'ensemble, vous ferez certainement mieux de faire cela d'une autre manière.

39
Michael Homer

La commande apropos est utile à bien des égards, mais elle vous donne aussi beaucoup de "déchets". La plupart des choses que vous répertoriez sont des routines de bibliothèque C (c'est à cela que sert la section 3 du manuel), que vous ne pouvez pas utiliser directement à partir du shell.

Pour les utiliser, vous devez écrire un programme C qui les appelle. Cela tombe en dehors de la gamme de sujets couverts par ce site particulier (ce serait sur le sujet à StackOverflow ).

Voici donc les réponses à vos questions:

  1. Vous ne pouvez pas, ce sont des routines de bibliothèque C.
  2. Vous ne pouvez pas, sauf si vous écrivez un programme C.

Je sais que vous le savez, mais pour être complet: dans le shell, si vous avez une chaîne dans une variable string, vous pouvez faire

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

Cela imprimera Length of string "hello world" is 11 dans le terminal où le 11 vient de ${#string} qui s'étend jusqu'à la longueur de la chaîne dans $string.

En interne, le shell peut très bien utiliser l'un des appels de bibliothèque que vous avez répertoriés pour effectuer son calcul de longueur.

C'est le moyen le plus efficace pour obtenir la longueur d'une chaîne stockée dans une variable Shell, dans le Shell.

Notez également que ${#string} est ne extension des paramètres du shell POSIX , il est donc portable entre tous les shells qui revendiquent n'importe quel degré de conformité POSIX.

28
Kusalananda

Je ne ferais pas cela uniquement pour strlen(), mais c'est une astuce utile pour essayer le code C parfois.

 user @ Host: ~ $ gdb gdb 
 (gdb) start 
 Point d'arrêt temporaire 1, ... dans main () 
 (gdb) print strlen (" foobar ") 
 1 $ = 6 

Ici gdb est le débogueur GNU, et il faudrait normalement un nom de programme pour le déboguer après. Parce que nous n'en avons pas, cet exemple le donne lui-même pour déboguer. Puis start démarre le programme, et après cela gdb peut être utilisé pour exécuter du code C arbitraire.

15
jpa

Un outil qui peut être utilisé pour appeler de manière interactive des fonctions dans des bibliothèques partagées: la "Witchcraft Compiler Collection". https://github.com/endrazine/wcc

Depuis la page GitHub:

wsh: La coquille de sorcellerie

Le shell de sorcellerie accepte les bibliothèques partagées ELF, les exécutables ELF ET_DYN et les scripts de shell Witchcraft écrits en Punk-C comme entrée. Il charge tous les exécutables dans son propre espace d'adressage et rend leur API disponible pour la programmation dans son interpréteur intégré. Cela fournit des fonctionnalités binaires similaires à celles fournies via la réflexion sur des langages comme Java.

Exemple d'utilisation de wsh La commande suivante charge l'exécutable /usr/sbin/Apache2 Dans wsh, appelle la fonction ap_get_server_banner() dans Apache pour récupérer sa bannière et l'afficher dans l'interpréteur wsh.

jonathan@blackbox:~$ wsh /usr/sbin/Apache2
> a = ap_get_server_banner()
> print(a)
Apache/2.4.7
4
Alex D