शेल से लाइब्रेरी कमांड कैसे निष्पादित करें?


27

मैं बस एक स्ट्रिंग की लंबाई की गणना करना चाहता था (यह हैश मान है)। इसलिए, मैंने टर्मिनल खोला और यह किया:

$ apropos length

उन आदेशों / कार्यों के एक समूह के साथ मुझे वापस लौटाया (3)या जिनके (3ssl)अंत में जोड़ा गया। अब आदमी आदमी हमें इन बातों के बारे में जानकारी देता section numbersहै।

3   Library calls (functions within program libraries)

जिज्ञासा से बाहर, मैंने इन सभी आदेशों के साथ प्रयास किया (उम्मीद है कि कम से कम एक काम करेगा)

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

और हर कमांड के लिए एक ही त्रुटि के अलावा कुछ नहीं मिला

$ strnlen HelloWorld 
$ strnlen: command not found

ठीक है, मैं जानता हूँ कि कैसे खोल में स्ट्रिंग की लंबाई को खोजने के लिए का उपयोग कर wc -m, expr lengthऔर अन्य समाधान।

लेकिन, मेरे यहाँ 2 प्रश्न हैं:

  1. शेल के अंदर किसीlibrary calls (3) का उपयोग कैसे करें ?
  2. सिर्फ लाइब्रेरी कॉल और अन्य कमांड का उपयोग करके स्ट्रिंग की लंबाई की गणना कैसे करें?

नोट: प्रश्न सामान्य रूप से library callsऔर शेल में उनके उपयोग पर केंद्रित है । यह उत्तर देने के लिए पहले प्रश्न को अधिक महत्वपूर्ण बनाता है।


stackoverflow.com/q/49719554/841108 एक निकट डुप्लिकेट है
बेसिल स्टायरनेविच

4
असल में, हालांकि माइकल का जवाब एक महान हैक है, सीधा जवाब है: आप नहीं। लाइब्रेरी कॉल शेल से संबंधित नहीं हैं । उनका उपयोग सी भाषा में कार्यक्रम लिखने के लिए किया जाता है। - आम तौर पर, जब manpages पढ़ने, जब तक आप एक कार्यक्रम कोडिंग कर रहे हैं, सिर्फ उपेक्षा वर्गों 2, 3 और 9
spectras

ऑफ टॉपिक, लेकिन ओपनवीएमएस में "लेक्सिकल" फ़ंक्शन हैं जो सिस्टम लाइब्रेरी फ़ंक्शंस के एक महान सौदे के लिए शेल इंटरफेस हैं।
रॉनजॉन

जवाबों:


39

आपको शायद ऐसा नहीं करना चाहिए , लेकिन आप कर सकते हैं। कुसलानंद का जवाब हाथ में काम के लिए बेहतर है और इस मुद्दे को समझाता है। चूंकि आपने विशेष रूप से टर्मिनल के अंदर किसी भी पुस्तकालय कॉल का उपयोग करने का तरीका पूछा था , हालांकि, यहां कुछ तरीके हैं ...


टिनी सी संकलक ( tcc) एक का समर्थन करता है -runझंडा ताकि आप, आप की सुविधा देता है (प्रभाव में) एक छोटे से कार्यक्रम लिख कर सी कोड की व्याख्या कर सकते हैं कि के एक एकल मंगलाचरण के माध्यम से टर्मिनल के अंदर किसी भी पुस्तकालय कॉल का उपयोग करें।

आप strnlenफ़ंक्शन को इस तरह से चला सकते हैं :

$ 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

यह बैश, zsh और अन्य गोले से प्रक्रिया प्रतिस्थापन का उपयोग करता हैtcc ताकि पढ़ने के लिए एक फ़ाइल दे सके जो सभी echos के परिणामों को सम्‍मिलित करता है ; अन्य विकल्प हैं।

आप इसे बनाने के लिए एक समारोह बना सकते हैं:

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

(मैंने strlenयहां इसलिए इस्तेमाल किया है कि यह एक unary function string-> int है - आपको प्रत्येक अलग-अलग एरिटी और रिटर्न टाइप के लिए एक अलग फ़ंक्शन की आवश्यकता होगी)।


एक अन्य विकल्प है बैश प्लगइन टेविस ओरमैंडी है, जो ऊपर लपेटता द्वारा और । यह संभवत: निकटतम सन्निकटन है जो आप कोशिश कर रहे थे। आप उदाहरण के लिए उपयोग कर सकते हैं:ctypes.shdlopendlsym

$ dlcall -r uint64 strlen "hello world"

और यह अपेक्षित रूप से फ़ंक्शन को कॉल करेगा।

यह "टर्मिनल से" ऐसा करने का सबसे सीधा तरीका है, लेकिन यह आपके वितरण पैकेजों के कुछ होने की संभावना नहीं है, इसलिए आपको इसे मैन्युअल रूप से स्थापित करना होगा (जो कि अप्रभावी है)। यहाँ अपनी वेबसाइट सेctypes.sh कुछ जानकारीपूर्ण उद्धरण दिए गए हैं ताकि लोग यह महसूस कर सकें कि ऐसा करने के बारे में लोग क्या सोचते हैं:

  • "बकवास"
  • "इसे रोकना होगा"
  • "आप इसके साथ बहुत दूर चले गए हैं"

अन्य गोले के समान उपकरण हो सकते हैं, लेकिन मैं उनके बारे में नहीं जानता। सिद्धांत रूप में इसका कोई कारण नहीं है कि एक स्टैंडअलोन कमांड नहीं हो सकता है जो बिल्कुल सरल मामलों के लिए किया था, लेकिन मुझे आश्चर्य है कि मैं एक को खोजने में सक्षम नहीं हूं ...


... तो मैंने एक बना दिया! dlcallआपको कमांड लाइन से लाइब्रेरी फ़ंक्शन को कॉल करने देता है :

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

यह फ़ंक्शन प्रोटोटाइप के सीमित सेट का समर्थन करता है, यह वर्तमान में बहुत विश्वसनीय या लचीला नहीं है, लेकिन यह अब मौजूद है।


आप उदाहरण के लिए, पायथन औरpython -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world का भी उपयोग कर सकते हैं , लेकिन यह निश्चित रूप से इसके बारे में जाने का सबसे आसान तरीका नहीं है। पर्ल, रूबी और अन्य भाषाओं में समान विशेषताएं हैं जिनका आप उपयोग कर सकते हैं।


तो आपके सवालों के जवाब हैं:

  1. ऊपर दिए गए तरीकों में से एक का उपयोग करें।
  2. आपको लाइब्रेरी में आपको बूटस्ट्रैप करने के लिए एक अन्य कमांड का उपयोग करने की आवश्यकता है, या सॉफ़्टवेयर का एक टुकड़ा जो आपके शेल में हुक करता है।

सब सब में, आप लगभग निश्चित रूप से किसी भी अन्य तरीके से ऐसा करना बेहतर होगा।


2
"dlcall" की याद दिलाता है (काफी समान नहीं) Windows "rundll": support.microsoft.com/en-gb/help/164787/…
pjc50

1
@ pjc50: सार्वजनिक सेवा घोषणा: मनमाने कार्यों को कॉल करने के लिए rundll32 एक सामान्य उद्देश्य उपकरण नहीं है । यह केवल दिए गए हस्ताक्षर के साथ फ़ंक्शन को कॉल करने के लिए उपयोग किया जा सकता है। इसके अलावा, यह बहुत भविष्य के सबूत नहीं है
केविन

29

aproposआदेश कई मायनों में उपयोगी है, लेकिन यह आप "जंक" का एक बहुत भी देता है। आपके द्वारा सूचीबद्ध की जाने वाली अधिकांश चीजें सी लाइब्रेरी रूटीन हैं (यह मैनुअल के सेक्शन 3 के लिए है), जिसे आप सीधे शेल से उपयोग नहीं कर सकते हैं।

उनका उपयोग करने के लिए, आपको सी प्रोग्राम लिखना होगा जो उन्हें कॉल करता है। यह इस विशेष साइट (यह StackOverflow पर विषय पर होगा ) द्वारा कवर किए गए विषयों की श्रेणी से बाहर है ।

इस प्रकार, आपके प्रश्नों के उत्तर हैं:

  1. आप नहीं कर सकते, वे सी लाइब्रेरी रूटीन हैं।
  2. जब तक आप C प्रोग्राम नहीं लिखते, आप नहीं कर सकते।

मुझे पता है कि आप यह जानते हैं, लेकिन पूर्णता के लिए: शेल में, यदि आपके पास एक चर में स्ट्रिंग है string, तो आप ऐसा कर सकते हैं

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

यह Length of string "hello world" is 11उस टर्मिनल में प्रिंट होगा जहां से 11आता है ${#string}जिसमें स्ट्रिंग की लंबाई तक विस्तार होता है $string

आंतरिक रूप से, शेल अच्छी तरह से लाइब्रेरी कॉल में से एक का उपयोग कर सकता है जिसे आपने इसकी लंबाई गणना करने के लिए सूचीबद्ध किया था।

यह एक स्ट्रिंग चर की लंबाई प्राप्त करने का सबसे कुशल तरीका है जो शेल चर में, शेल में संग्रहीत किया जाता है।

नोट भी है कि ${#string}है एक POSIX खोल पैरामीटर विस्तार , यह इसलिए सभी गोले POSIX अनुपालन के किसी भी स्तर का दावा है कि दोनों के बीच पोर्टेबल है।


लाइब्रेरी फ़ंक्शंस के बारे में एक अच्छी व्याख्या है, लेकिन इस उत्तर के बाकी हिस्से थोड़ा भ्रामक हैं। ओपी कहते हैं "मैं एक स्ट्रिंग की लंबाई की गणना करना चाहता था" यहां उपयोग करने की कोई आवश्यकता नहीं printfहै। यदि आप इसे वाक्य के भाग के रूप में प्रिंट करना चाहते हैं तो वह सबसे अच्छा तरीका हो सकता है। लेकिन "मैं एक स्ट्रिंग की लंबाई कैसे प्राप्त करूं" के सवाल का जवाब? है ${#string}हिस्सा है, नहीं printf। आप बस echo ${#string}अगर आप सिर्फ लंबाई का उत्पादन करना चाहते हैं, या इसे किसी अन्य चर के साथ string_length=${#string}या जो आप चाहते हैं, उसे असाइन कर सकते हैं। Printf वास्तव में प्रासंगिक नहीं है
Adam

1
@ अदम मैंने जवाब में छोटे संशोधन किए हैं। मुझे लगता है कि यह बहुत स्पष्ट है कि स्ट्रिंग की लंबाई कैसे प्राप्त की जाए और उपयोगकर्ता पहले ही कह चुके हैं कि वे जानते हैं कि यह कैसे करना है। तक का उपयोग कर के साथ स्ट्रिंग की लंबाई printfमैं सिर्फ "उपयोग कह के अलावा कुछ जोड़ने ${#string}(जो उदाहरण से स्वयं स्पष्ट है)"।
Kusalananda

15

मैं यह सिर्फ के लिए नहीं होगा strlen(), लेकिन यह कभी कभी सी कोड की कोशिश करने के लिए एक उपयोगी चाल है।

user @ host: ~ $ gdb gdb
(gdb) प्रारंभ
अस्थायी ब्रेकपॉइंट 1, ... मुख्य ()
(gdb) प्रिंट स्ट्रलेन ("फोब्बर")
$ 1 = 6

यहाँ gdbGNU डिबगर है, और यह आम तौर पर इसके बाद डिबग करने के लिए एक प्रोग्राम नाम लेगा। क्योंकि हमारे पास कोई नहीं है, यह उदाहरण इसे डीबग करने के लिए देता है। फिर startकार्यक्रम शुरू करता है, और उसके बाद gdbमनमाने सी कोड को निष्पादित करने के लिए इस्तेमाल किया जा सकता है।


2
अच्छी चाल, gdb का उपयोग करने के लिए। फिर भी gdb डेवलपर टूल का हिस्सा है, और यदि आप लाइब्रेरी फ़ंक्शन का उपयोग करना चाहते हैं, तो आप डेवलपर टूल का उपयोग करने के लिए सीखने की बेहतर तैयारी करते हैं।
डूडी बॉय

4

एक उपकरण जिसका उपयोग साझा पुस्तकालयों में अंतःक्रियात्मक रूप से कॉल कार्यों के लिए किया जा सकता है: "विचक्राफ्ट संकलक संग्रह"। https://github.com/endrazine/wcc

GitHub पेज से:

wsh: जादू टोना खोल

जादू टोना ईएलएफ साझा पुस्तकालयों, इनपुट के रूप में पंक-सी में लिखे गए पुस्तकालयों, ईएलएफ ET_DYN के निष्पादन और जादू टोना शैल लिपियों को स्वीकार करता है। यह अपने स्वयं के पते के स्थान में सभी निष्पादनों को लोड करता है और अपने एपीआई को अपने एम्बेडेड दुभाषिया में प्रोग्रामिंग के लिए उपलब्ध कराता है। यह बाइनरी फ़ंक्शंस के लिए प्रदान करता है जो जावा जैसी भाषाओं पर प्रतिबिंब के माध्यम से प्रदान करता है।

Wsh का उदाहरण उपयोग निम्न आदेश /usr/sbin/apache2wsh के भीतर निष्पादन योग्य को लोड करता है , ap_get_server_banner()अपने बैनर को पुनः प्राप्त करने के लिए अपाचे के भीतर फ़ंक्शन को कॉल करता है और wshदुभाषिया के भीतर प्रदर्शित करता है ।

jonathan@blackbox:~$ wsh /usr/sbin/apache2
> a = ap_get_server_banner()
> print(a)
Apache/2.4.7
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.