Bagaimana cara menjalankan perintah library dari shell?

27

Saya hanya ingin menghitung panjang string (yaitu nilai hash). Jadi, saya membuka terminal dan melakukan ini:

$ apropos length

yang mengembalikan saya dengan banyak perintah / fungsi yang telah (3)atau (3ssl)ditambahkan pada akhir dari mereka. Sekarang manusia memberi kita informasi tentang apa section numbersartinya ini .

3   Library calls (functions within program libraries)

Karena penasaran, saya hanya mencoba dengan semua perintah ini (dengan harapan setidaknya satu akan bekerja)

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

dan mendapat apa-apa selain kesalahan yang sama untuk setiap perintah

$ strnlen HelloWorld 
$ strnlen: command not found

Yah, saya tahu cara menemukan panjang string di shell menggunakan wc -m, expr lengthdan solusi lainnya.

Tapi, saya punya 2 pertanyaan di sini:

  1. Cara menggunakan salahlibrary calls (3) dalam shell?
  2. Bagaimana cara menghitung panjang string hanya dengan menggunakan panggilan perpustakaan dan bukan perintah lain?

CATATAN: Pertanyaan berfokus secara umum library callsdan penggunaannya dalam shell. Itu membuat pertanyaan pertama lebih penting untuk dijawab.

C0deDaedalus
sumber
stackoverflow.com/q/49719554/841108 adalah duplikat dekat
Basile Starynkevitch
4
Pada dasarnya, meskipun jawaban Michael adalah peretasan hebat, jawaban langsungnya adalah: Anda tidak. Panggilan perpustakaan tidak terkait dengan shell. Mereka digunakan untuk menulis program dalam bahasa C. - Lebih umum, ketika membaca halaman manual, kecuali jika Anda sedang mengkode suatu program, abaikan saja bagian 2, 3 dan 9.
spectras
Off Topic, tetapi OpenVMS memiliki fungsi "leksikal" yang merupakan antarmuka shell ke banyak fungsi pustaka sistem.
RonJohn

Jawaban:

39

Anda mungkin tidak seharusnya melakukan ini, tetapi Anda bisa. Jawaban Kusalananda lebih baik untuk tugas yang ada dan menjelaskan masalahnya. Karena Anda memang bertanya secara spesifik bagaimana cara menggunakannya panggilan perpustakaan apa pun di dalam terminal, inilah beberapa cara ...


The kecil C Compiler ( tcc) mendukung -runbendera yang memungkinkan Anda (berlaku) menafsirkan kode C dengan menulis program kecil, sehingga Anda dapat menggunakan panggilan perpustakaan di dalam terminal melalui doa tunggal itu.

Anda dapat menjalankan strnlen fungsi seperti ini:

$ 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

Ini menggunakan proses substitusi dari Bash, zsh, dan shell lainnya untuk memberikan tccfile untuk dibaca yang tampaknya berisi hasil dari semua echos; ada opsi lain.

Anda dapat membuat fungsi untuk menghasilkan ini untuk Anda:

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

(Saya telah menggunakan di strlensini sehingga itu adalah fungsi unary string-> int - Anda akan memerlukan fungsi terpisah untuk setiap jenis arity dan return yang berbeda).


Pilihan lain adalah dengan ctypes.shBash Plugin oleh Tavis Ormandy, yang membungkus dlopendan dlsym. Ini mungkin perkiraan terdekat dengan apa yang Anda coba. Anda dapat menggunakan, misalnya:

$ dlcall -r uint64 strlen "hello world"

dan itu akan memanggil fungsi seperti yang diharapkan.

Ini adalah cara paling langsung untuk melakukannya "dari terminal", tetapi itu tidak mungkin menjadi sesuatu paket distribusi Anda sehingga Anda harus menginstalnya secara manual (yang tidak trivial). Berikut adalah beberapa kutipanctypes.sh informatif dari situs web sendiri untuk memberikan kesan umum tentang bagaimana perasaan orang tentang melakukan ini:

  • "Itu menjijikkan"
  • "ini harus dihentikan"
  • "Kamu sudah terlalu jauh dengan ini"

Mungkin ada alat serupa untuk kerang lain, tapi saya tidak tahu tentang mereka. Secara teori tidak ada alasan tidak mungkin ada perintah mandiri yang melakukan ini tepat untuk kasus-kasus sederhana, tetapi saya agak terkejut saya belum dapat menemukan satu ...


... jadi saya membuat satu! dlcallmemungkinkan Anda memanggil fungsi perpustakaan dari baris perintah :

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

Ini mendukung serangkaian fungsi prototipe terbatas, itu tidak terlalu dapat diandalkan atau tangguh saat ini, tetapi sekarang ada.


Anda juga bisa menggunakan, misalnya, Python danpython -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world , tetapi tentu saja itu bukan cara termudah untuk melakukannya. Perl, Ruby, dan bahasa lain memiliki fitur serupa yang dapat Anda gunakan.


Jadi jawaban atas pertanyaan Anda adalah:

  1. Gunakan salah satu pendekatan di atas.
  2. Anda tidak perlu menggunakan perintah lain untuk bootstrap Anda ke perpustakaan, atau software yang kait ke shell Anda.

Secara keseluruhan, Anda hampir pasti lebih baik melakukan ini dengan cara lain.

Michael Homer
sumber
2
"dlcall" mengingatkan saya pada (tidak persis sama) Windows "rundll": support.microsoft.com/en-gb/help/164787/…
pjc50
1
@ pjc50: Pengumuman layanan publik: rundll32 bukan alat tujuan umum untuk memanggil fungsi sewenang-wenang . Ini hanya dapat digunakan untuk memanggil fungsi dengan tanda tangan yang diberikan. Juga, itu tidak terlalu bukti di masa depan .
Kevin
29

Itu apropos Perintah ini berguna dalam banyak cara, tetapi tidak memberikan banyak "sampah" juga. Sebagian besar hal yang Anda daftarkan adalah rutinitas pustaka C (ini adalah bagian apa dari manual ini), yang tidak dapat Anda gunakan langsung dari shell.

Untuk menggunakannya, Anda harus menulis program C yang memanggil mereka. Ini berada di luar kisaran topik yang dicakup oleh situs khusus ini (itu akan menjadi topik di StackOverflow ).

Jadi, inilah jawaban untuk pertanyaan Anda:

  1. Anda tidak bisa, mereka adalah rutinitas perpustakaan C.
  2. Anda tidak bisa, kecuali Anda menulis program C.

Saya tahu Anda tahu ini, tetapi demi kelengkapan: Di shell, jika Anda memiliki string dalam variabel string, Anda dapat melakukan

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

Ini akan mencetak Length of string "hello world" is 11di terminal tempat 11asalnya ${#string}yang memanjang hingga panjang string$string .

Secara internal, shell mungkin menggunakan salah satu panggilan perpustakaan yang Anda daftarkan untuk melakukan perhitungan panjangnya.

Ini adalah cara paling efisien untuk mendapatkan panjang string yang disimpan dalam variabel shell, di shell.

Perhatikan juga bahwa itu ${#string}adalah perluasan parameter shell POSIX , oleh karena itu portabel di antara semua shell yang mengklaim tingkat kepatuhan POSIX.

Kusalananda
sumber
Bagian-bagian tentang fungsi perpustakaan adalah penjelasan yang baik, tetapi sisa dari jawaban ini agak menyesatkan. OP mengatakan "Saya ingin menghitung panjang string" Tidak perlu digunakan di printfsini. Jika Anda ingin mencetaknya sebagai bagian dari kalimat maka itu mungkin cara terbaik. Tetapi jawaban atas pertanyaan "bagaimana saya mendapatkan panjang tali?" adalah ${#string}bagian, bukan printf. Anda bisa hanya echo ${#string}jika Anda hanya ingin output panjangnya saja, atau menugaskannya ke variabel lain dengan string_length=${#string}atau apa pun yang Anda inginkan. printf tidak benar-benar relevan
Adam
1
@ Adam Saya telah membuat modifikasi kecil untuk jawabannya. Saya pikir cukup jelas bagaimana cara mendapatkan panjang tali dan pengguna telah mengatakan mereka tahu bagaimana cara melakukannya. Dengan menggunakan panjang string dengan printfsaya menambahkan sesuatu selain hanya mengatakan "gunakan ${#string}" (yang jelas dari contoh).
Kusalananda
15

Saya tidak akan melakukan ini hanya strlen(), tetapi ini adalah trik yang berguna untuk mencoba kode C kadang-kadang

user @ host: ~ $ gdb gdb
(gdb) mulai
Breakpoint sementara 1, ... pada main ()
(gdb) print strlen ("foobar")
$ 1 = 6

Ini gdbadalah debugger GNU, dan biasanya diperlukan nama program untuk debug setelahnya. Karena kita tidak memilikinya, contoh ini memberikannya sendiri untuk debug. Kemudian startmulai program, dan setelah itu gdbdapat digunakan untuk mengeksekusi kode C sewenang-wenang.

jpa
sumber
2
Trik yang bagus, menggunakan gdb. Namun gdb adalah bagian dari alat pengembang, dan jika Anda ingin menggunakan fungsi perpustakaan, Anda lebih baik bersiap untuk belajar menggunakan alat pengembang.
Dudi Boy
4

Alat yang dapat digunakan untuk memanggil fungsi secara interaktif di pustaka bersama: "Koleksi Penyihir Witchcraft". https://github.com/endrazine/wcc

Dari halaman GitHub:

wsh: Shell Sihir

Shell sihir menerima perpustakaan bersama ELF, executable ELF ET_DYN dan Script Shell sihir yang ditulis dalam Punk-C sebagai input. Itu memuat semua executable di ruang alamatnya sendiri dan membuat API mereka tersedia untuk pemrograman dalam interpreter yang disematkan. Ini menyediakan fungsionalitas binari yang mirip dengan yang disediakan melalui refleksi pada bahasa seperti Java.

Contoh penggunaan wsh Perintah berikut memuat /usr/sbin/apache2executable dalam wsh, memanggil ap_get_server_banner()fungsi di dalam apache untuk mengambil spanduknya dan menampilkannya di dalam wshinterpreter.

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