Come eseguire i comandi della libreria dalla shell?


27

Volevo semplicemente calcolare la lunghezza di una stringa (che è il valore hash). Quindi, ho aperto il terminale e ho fatto questo:

$ apropos length

che mi ha restituito un gruppo di comandi / funzioni che hanno (3)o (3ssl)aggiunto alla fine di essi. Ora man man ci dà informazioni sul section numberssignificato di questi .

3   Library calls (functions within program libraries)

Per curiosità, ho appena provato con tutti questi comandi (nella speranza che almeno uno funzionasse)

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

e ottenuto nient'altro che lo stesso errore per ogni comando

$ strnlen HelloWorld 
$ strnlen: command not found

Beh, io so come trovare la lunghezza di corda in guscio utilizzando wc -m, expr lengthe altre soluzioni alternative.

Ma ho 2 domande qui:

  1. Come usare qualsiasilibrary calls (3) all'interno della shell?
  2. Come calcolare la lunghezza della stringa usando solo le chiamate in libreria e non altri comandi?

NOTA: la domanda si concentra in generale library callse sul loro utilizzo nella shell. Ciò rende la prima domanda più importante a cui rispondere.



4
Fondamentalmente, sebbene la risposta di Michael sia un grande trucco, la risposta semplice è: non lo fai. Le chiamate in libreria non sono correlate alla shell. Sono usati per scrivere programmi in linguaggio C. - Più in generale, quando leggi le manpage, a meno che tu non stia codificando un programma, ignora le sezioni 2, 3 e 9.
extra

Fuori tema, ma OpenVMS ha funzioni "lessicali" che sono interfacce di shell per una grande quantità di funzioni di libreria di sistema.
RonJohn,

Risposte:


39

Probabilmente non dovresti farlo, ma puoi. La risposta di Kusalananda è migliore per il compito da svolgere e spiega il problema. Dato che hai chiesto in modo specifico come utilizzare qualsiasi chiamata in libreria all'interno del terminale, ecco alcuni modi ...


Il minuscolo compilatore C ( tcc) supporta un -runflag che consente (in effetti) di interpretare il codice C scrivendo un piccolo programma, in modo da poter utilizzare qualsiasi chiamata della libreria all'interno del terminale tramite un'unica chiamata.

È possibile eseguire la strnlenfunzione in questo modo:

$ 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

Questo utilizza la sostituzione del processo da Bash, zsh e altre shell per dare tccun file da leggere che sembra contenere i risultati di tutti echoi messaggi; ci sono altre opzioni.

Potresti creare una funzione per generare questo per te:

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

(Ho usato strlenqui in modo che sia una stringa di funzione unaria-> int - avresti bisogno di una funzione separata per ogni diverso arity e tipo di ritorno).


Un'altra opzione è il ctypes.shplug-in Bash di Tavis Ormandy, che si chiude dlopene dlsym. Questa è probabilmente l'approssimazione più vicina a ciò che stavi provando. Puoi usare, ad esempio:

$ dlcall -r uint64 strlen "hello world"

e chiamerà la funzione come previsto.

Questo è il modo più diretto per farlo "dal terminale", ma è improbabile che si tratti di un pacchetto di distribuzione, quindi dovresti installarlo manualmente (che non è banale). Ecco alcune citazionictypes.sh informative dal proprio sito Web per dare un'idea generale di come le persone si sentono a farlo:

  • "è disgustoso"
  • "questo deve finire"
  • "sei andato troppo lontano con questo"

Potrebbero esserci strumenti simili per altre shell, ma non ne sono a conoscenza. In teoria non c'è motivo per cui non ci potrebbe essere un comando autonomo che ha fatto esattamente questo per i casi semplici, ma sono un po 'sorpreso di non essere stato in grado di trovarne uno ...


... quindi ne ho creato uno! dlcallconsente di chiamare le funzioni di libreria dalla riga di comando :

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

Supporta un set limitato di prototipi di funzioni, attualmente non è estremamente affidabile o resiliente, ma ora esiste.


Potresti anche usare, ad esempio, Python epython -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world , ma non è certamente il modo più semplice per farlo. Perl, Ruby e altre lingue hanno caratteristiche simili che potresti usare.


Quindi le risposte alle tue domande sono:

  1. Utilizzare uno degli approcci sopra.
  2. È Non è necessario utilizzare un altro comando per il bootstrap voi in biblioteca, o un pezzo di software che ami nel tuo guscio.

Tutto sommato, sarà quasi sicuramente meglio farlo in qualsiasi altro modo.


2
"dlcall" mi ricorda (non del tutto identico) Windows "rundll": support.microsoft.com/en-gb/help/164787/…
pjc50

1
@ pjc50: annuncio di servizio pubblico: rundll32 non è uno strumento generico per chiamare funzioni arbitrarie . Può essere utilizzato solo per chiamare funzioni con una data firma. Inoltre, non è terribilmente a prova di futuro .
Kevin,

29

Il aproposcomando è utile in molti modi, ma ti dà anche molta "spazzatura". La maggior parte delle cose che elenchi sono routine di libreria C (questo è lo scopo della sezione 3 del manuale), che non puoi usare direttamente dalla shell.

Per usarli, dovresti scrivere il programma C che li chiama. Ciò non rientra nella gamma di argomenti trattati da questo particolare sito (sarebbe in argomento su StackOverflow ).

Queste, quindi, sono le risposte alle tue domande:

  1. Non puoi, sono routine di libreria C.
  2. Non puoi, a meno che tu non scriva un programma C.

So che lo sai, ma per completezza: nella shell, se hai una stringa in una variabile string, puoi farlo

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

Questo verrà stampato Length of string "hello world" is 11nel terminale da cui 11proviene il ${#string}che si espande alla lunghezza della stringa $string.

Internamente, la shell potrebbe usare una delle chiamate della libreria elencate per eseguire il calcolo della lunghezza.

Questo è il modo più efficiente per ottenere la lunghezza di una stringa archiviata in una variabile shell, nella shell.

Si noti inoltre che si ${#string}tratta di un'espansione dei parametri della shell POSIX , pertanto è portatile tra tutte le shell che rivendicano qualsiasi grado di conformità POSIX.


Le parti relative alle funzioni della libreria sono una buona spiegazione, ma il resto di questa risposta è un po 'fuorviante. OP dice "Volevo semplicemente calcolare la lunghezza di una stringa" Non c'è bisogno di usare printfqui. Se vuoi stamparlo come parte della frase, questo potrebbe essere il modo migliore. Ma la risposta alla domanda "come posso ottenere la lunghezza di una stringa?" è la ${#string}parte, non la stampa. Puoi solo echo ${#string}se vuoi solo produrre l'output della lunghezza o assegnarlo a un'altra variabile con string_length=${#string}o qualunque cosa tu voglia. printf non è rilevante
Adam

1
@Adam Ho apportato piccole modifiche alla risposta. Penso che sia abbastanza chiaro come ottenere la lunghezza della stringa e l'utente ha già detto di saperlo fare. Con l' utilizzo della lunghezza della stringa con printfaggiungo qualcosa di diverso solo dicendo "uso ${#string}" (che è di per sé evidente dall'esempio).
Kusalananda

15

Non lo farei solo per strlen(), ma è un trucco utile per provare il codice C a volte.

user @ host: ~ $ gdb gdb
(gdb) avvia
Punto di interruzione temporaneo 1, ... in main ()
(gdb) print strlen ("foobar")
$ 1 = 6

Ecco gdbil debugger GNU, e normalmente ci vorrebbe un nome di programma per eseguire il debug dopo di esso. Poiché non ne abbiamo nessuno, questo esempio si dà al debug. Quindi startavvia il programma e successivamente gdbpuò essere utilizzato per eseguire codice C arbitrario.


2
Bel trucco, per usare gdb. Tuttavia gdb fa parte degli strumenti di sviluppo e, se si desidera utilizzare la funzione di libreria, è meglio prepararsi ad imparare a utilizzare gli strumenti di sviluppo.
Dudi Boy,

4

Uno strumento che può essere utilizzato per chiamare in modo interattivo funzioni nelle librerie condivise: la "Collezione di compilatori di stregoneria". https://github.com/endrazine/wcc

Dalla pagina GitHub:

wsh: The Witchcraft shell

La shell witchcraft accetta librerie condivise ELF, eseguibili ELF ET_DYN e script di shell Witchcraft scritti in Punk-C come input. Carica tutti gli eseguibili nel proprio spazio di indirizzi e rende le loro API disponibili per la programmazione nel suo interprete incorporato. Ciò fornisce funzionalità binarie simili a quelle fornite tramite la riflessione su linguaggi come Java.

Esempio di utilizzo di wsh Il seguente comando carica l' /usr/sbin/apache2eseguibile in wsh, chiama la ap_get_server_banner()funzione in apache per recuperare il suo banner e lo visualizza all'interno wshdell'interprete.

jonathan@blackbox:~$ wsh /usr/sbin/apache2
> a = ap_get_server_banner()
> print(a)
Apache/2.4.7
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.