Làm thế nào để thực thi các lệnh thư viện từ shell?


27

Tôi muốn chỉ đơn giản là tính toán độ dài của một chuỗi (đó là giá trị băm). Vì vậy, tôi đã mở terminal và làm điều này:

$ apropos length

điều đó trả về cho tôi với một loạt các lệnh / hàm có (3)hoặc được (3ssl)thêm vào cuối chúng. Hiện nay người đàn ông cung cấp cho chúng tôi thông tin về những gìsection numberscó nghĩa là.

3   Library calls (functions within program libraries)

Vì tò mò, tôi chỉ thử với tất cả các lệnh này (với hy vọng ít nhất một lệnh sẽ hoạt động)

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

và không có gì ngoài lỗi tương tự cho mỗi lệnh

$ strnlen HelloWorld 
$ strnlen: command not found

Vâng, tôi biết làm thế nào để tìm độ dài của chuỗi trong shell sử dụng wc -m, expr lengthvà cách giải quyết khác.

Nhưng, tôi có 2 câu hỏi ở đây:

  1. Cách sử dụng bất kỳlibrary calls (3) bên trong vỏ?
  2. Làm thế nào để tính toán độ dài chuỗi chỉ bằng các lệnh gọi thư viện và không phải các lệnh khác?

LƯU Ý: Câu hỏi tập trung nói chung library callsvà cách sử dụng của chúng trong vỏ. Điều đó làm cho câu hỏi đầu tiên quan trọng hơn để trả lời.



4
Về cơ bản, mặc dù câu trả lời của Michael là một bản hack tuyệt vời, nhưng câu trả lời đơn giản là: bạn không. Các cuộc gọi thư viện không liên quan đến vỏ. Chúng được sử dụng để viết chương trình bằng ngôn ngữ C. - Tổng quát hơn, khi đọc các trang hướng dẫn, trừ khi bạn đang mã hóa chương trình, chỉ cần bỏ qua các phần 2, 3 và 9.
phổ

Ngoài chủ đề, nhưng OpenVMS có các chức năng "từ vựng" là các giao diện hệ vỏ với rất nhiều chức năng thư viện hệ thống.
RonJohn

Câu trả lời:


39

Bạn có thể không nên làm điều này, nhưng bạn có thể. Câu trả lời của Kusalananda là tốt hơn cho nhiệm vụ trong tay và giải thích vấn đề. Vì bạn đã hỏi cụ thể cách sử dụng bất kỳ cuộc gọi thư viện nào bên trong thiết bị đầu cuối, tuy nhiên, đây là một vài cách ...


Các C Compiler Tiny ( tcc) hỗ trợ một -runlá cờ cho phép bạn (có hiệu lực) giải thích mã C bằng cách viết một chương trình nhỏ, vì vậy bạn có thể sử dụng bất kỳ cuộc gọi thư viện bên trong thiết bị đầu cuối thông qua một invocation duy nhất đó.

Bạn có thể chạy strnlenchức năng như thế này:

$ 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

Điều này sử dụng thay thế quá trình từ Bash, zsh và các shell khác để cung cấp tccmột tệp để đọc có vẻ như chứa kết quả của tất cảecho s; Có những lựa chọn khác.

Bạn có thể tạo một hàm để tạo cái này cho bạn:

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

(Tôi đã sử dụng strlenở đây để nó là một chuỗi hàm unary-> int - bạn cần một hàm riêng cho từng loại trả về và mức độ khác nhau).


Một lựa chọn khác là các ctypes.shPlugin Bash bởi Tavis Ormandy, mà kết thúc tốt đẹp dlopendlsym. Đây có lẽ là gần đúng nhất với những gì bạn đã cố gắng. Bạn có thể sử dụng, ví dụ:

$ dlcall -r uint64 strlen "hello world"

và nó sẽ gọi hàm như mong đợi.

Đây là cách trực tiếp nhất để thực hiện "từ thiết bị đầu cuối", nhưng không chắc là thứ gì đó phân phối các gói của bạn nên bạn phải cài đặt thủ công (không cần thiết). Dưới đây là một số trích dẫnctypes.sh thông tin từ trang web của chính mình để tạo ấn tượng chung về cách mọi người cảm nhận về việc này:

  • "thật kinh tởm"
  • "Điều này phải chấm dứt"
  • "bạn đã đi quá xa với điều này"

Có thể có các công cụ tương tự cho các shell khác, nhưng tôi không biết về chúng. Về lý thuyết, không có lý do gì không thể có một lệnh độc lập thực hiện chính xác các trường hợp đơn giản này, nhưng tôi hơi ngạc nhiên khi tôi không thể tìm thấy một ...


... Vì vậy, tôi đã thực hiện một! dlcallcho phép bạn gọi các chức năng thư viện từ dòng lệnh :

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

Nó hỗ trợ một bộ nguyên mẫu hàm hạn chế, hiện tại nó không đáng tin cậy hoặc có khả năng phục hồi, nhưng hiện tại nó đã tồn tại.


Bạn cũng có thể sử dụng, ví dụ như Python vàpython -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world , nhưng chắc chắn đó không phải là cách dễ nhất để nói về nó. Perl, Ruby và các ngôn ngữ khác có các tính năng tương tự bạn có thể sử dụng.


Vì vậy, câu trả lời cho câu hỏi của bạn là:

  1. Sử dụng một trong những cách tiếp cận ở trên.
  2. Bạn làm cần phải sử dụng lệnh khác để bootstrap bạn vào thư viện, hoặc một phần của phần mềm mà móc vào shell của bạn.

Nói chung, bạn gần như chắc chắn sẽ tốt hơn khi làm điều này theo bất kỳ cách nào khác.


2
"dlcall" nhắc nhở tôi về (không hoàn toàn giống hệt nhau) Windows "rundll": support.microsoft.com/en-gb/help/164787/...
pjc50

1
@ pjc50: Thông báo dịch vụ công cộng: rundll32 không phải là một công cụ có mục đích chung để gọi các hàm tùy ý . Nó chỉ có thể được sử dụng để gọi các chức năng với một chữ ký nhất định. Ngoài ra, nó không phải là bằng chứng trong tương lai .
Kevin

29

Các apropos lệnh rất hữu ích trong nhiều cách khác nhau, nhưng nó cung cấp cho bạn rất nhiều "rác" quá. Hầu hết những thứ bạn liệt kê là các thói quen của thư viện C (đây là phần 3 của hướng dẫn sử dụng), mà bạn không thể sử dụng trực tiếp từ trình bao.

Để sử dụng chúng, bạn sẽ phải viết chương trình C gọi chúng. Điều này nằm ngoài phạm vi các chủ đề được đề cập bởi trang web cụ thể này (nó sẽ nằm trong chủ đề tại StackOverflow ).

Đây là những câu trả lời cho câu hỏi của bạn:

  1. Bạn không thể, họ là thói quen thư viện C.
  2. Bạn không thể, trừ khi bạn viết chương trình C.

Tôi biết bạn biết điều này, nhưng vì lợi ích của sự hoàn chỉnh: Trong shell, nếu bạn có một chuỗi trong một biến string, bạn có thể làm

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

Điều này sẽ in Length of string "hello world" is 11trong thiết bị đầu cuối nơi 11xuất phát từ ${#string}chiều dài của chuỗi trong$string .

Trong nội bộ, shell có thể đang sử dụng một trong các cuộc gọi thư viện mà bạn đã liệt kê để thực hiện tính toán độ dài của nó.

Đây là cách hiệu quả nhất để có được độ dài của chuỗi được lưu trữ trong biến shell, trong shell.

Cũng lưu ý rằng đó ${#string}một mở rộng tham số shell POSIX , do đó, nó có thể di động giữa tất cả các shell yêu cầu bất kỳ mức độ tuân thủ POSIX nào.


Các phần về chức năng thư viện là một lời giải thích tốt, nhưng phần còn lại của câu trả lời này là một chút sai lệch. OP nói "Tôi muốn chỉ đơn giản là tính toán độ dài của chuỗi" Không cần sử dụng printfở đây. Nếu bạn muốn in nó ra như một phần của câu thì đó có thể là cách tốt nhất. Nhưng câu trả lời cho câu hỏi "làm thế nào để tôi có được độ dài của một chuỗi?" là ${#string}một phần, không phải là printf. Bạn có thể chỉ cần echo ${#string}bạn chỉ muốn xuất độ dài hoặc gán nó cho một biến khác với string_length=${#string}hoặc bất cứ điều gì bạn muốn. printf không thực sự phù hợp
Adam

1
@Adam Tôi đã thực hiện các sửa đổi nhỏ cho câu trả lời. Tôi nghĩ khá rõ ràng làm thế nào để có được độ dài của chuỗi và người dùng đã nói rằng họ biết cách thực hiện. Bằng cách sử dụng độ dài của chuỗi với printftôi thêm một cái gì đó ngoài việc chỉ nói "sử dụng ${#string}" (điều này là hiển nhiên từ ví dụ).
Kusalananda

15

Tôi sẽ không làm điều này chỉ strlen() , nhưng đôi khi nó là một mẹo hữu ích để thử mã C.

người dùng @ máy chủ: ~ $ gdb gdb
(gdb) bắt đầu
Điểm dừng tạm thời 1, ... trong chính ()
(gdb) in strlen ("foobar")
$ 1 = 6

Đây gdblà trình gỡ lỗi GNU và thông thường sẽ lấy tên chương trình để gỡ lỗi sau nó. Bởi vì chúng tôi không có, ví dụ này cung cấp cho chính nó để gỡ lỗi. Sau đó startkhởi động chương trình và sau đó gdbcó thể được sử dụng để thực thi mã C tùy ý.


2
Thủ thuật hay, để sử dụng gdb. Tuy nhiên, gdb là một phần của các công cụ dành cho nhà phát triển và nếu bạn muốn sử dụng chức năng thư viện, bạn nên chuẩn bị tốt hơn để học cách sử dụng các công cụ dành cho nhà phát triển.
Cậu bé Dudi

4

Một công cụ có thể được sử dụng để gọi các hàm tương tác trong các thư viện dùng chung: "Bộ sưu tập trình biên dịch Witchcraft". https://github.com/endrazine/wcc

Từ trang GitHub:

wsh: Vỏ phù thủy

Shell witchcraft chấp nhận các thư viện chia sẻ ELF, các tệp thực thi ELF ET_DYN và Witchcraft Shell Sc Script được viết bằng Punk-C làm đầu vào. Nó tải tất cả các tệp thực thi trong không gian địa chỉ của chính nó và làm cho API của chúng có sẵn để lập trình trong trình thông dịch nhúng. Điều này cung cấp cho các chức năng nhị phân tương tự như các chức năng được cung cấp thông qua sự phản chiếu trên các ngôn ngữ như Java.

Ví dụ sử dụng wsh Lệnh sau đây tải /usr/sbin/apache2tệp thực thi trong wsh, gọi ap_get_server_banner()hàm trong apache để lấy biểu ngữ của nó và hiển thị nó trong trình wshthông dịch.

jonathan@blackbox:~$ wsh /usr/sbin/apache2
> a = ap_get_server_banner()
> print(a)
Apache/2.4.7
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.