web-dev-qa-db-ja.com

シェルからライブラリコマンドを実行する方法は?

文字列(ハッシュ値)の長さを単純に計算したかったのです。だから、私はターミナルを開いてこれをしました:

_$ apropos length
_

その結果、_(3)_または_(3ssl)_が末尾に追加された一連のコマンド/関数が返されました。ここでman manは、これらの_section numbers_の意味についての情報を提供します。

_3   Library calls (functions within program libraries)
_

好奇心から、私はこれらすべてのコマンドを試してみました(少なくとも1つがうまくいくことを願っています)

_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. シェル内でany library calls (3)を使用する方法?
  2. ライブラリ呼び出しだけを使用して他のコマンドを使用せずに文字列の長さを計算する方法は?

注:質問では、一般的に_library calls_と、シェルでの使用に焦点を当てています。そのため、最初の質問に答えることがより重要になります。

27
C0deDaedalus

あなたはおそらくこれを行うべきではありませんが、できます。 Kusalanandaの回答 は、目前のタスクに適し、問題を説明します。端末内でanyライブラリ呼び出しを使用する方法を具体的に尋ねたので、ここにいくつかの方法があります...


Tiny Cコンパイラ(tcc)は_-run_フラグ をサポートしています。これにより、小さなプログラムを作成することで(事実上)Cコードを解釈できるため、can単一の呼び出しでターミナル内のライブラリ呼び出しを使用します。

次のように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
_

これは、Bash、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を使用して、単項関数string-> intにしています-異なるアリティと戻り値の型ごとに個別の関数が必要です)。


別のオプションは、Tavis Ormandyによる the _ctypes.sh_ Bash plugin で、dlopendlsymをラップします。これはおそらく、あなたが試みていたものに最も近い近似です。たとえば、次のように使用できます。

_$ dlcall -r uint64 strlen "hello world"
_

期待どおりに関数を呼び出します。

これは「ターミナルから」それを行う最も直接的な方法ですが、配布パッケージに含まれている可能性は低いため、手動でインストールする必要があります(これは重要です)。ここにいくつかの有益な _ctypes.sh_の自身のウェブサイトからの引用 がこれを行うことについて人々がどのように感じているかについての一般的な印象を与えるために:

  • 「嫌だ」
  • 「これは止めなければならない」
  • 「あなたはこれで行き過ぎました」

他のシェルにも同様のツールがあるかもしれませんが、私はそれらについて知りません。理論的には、単純なケースでこれを正確に実行するスタンドアロンコマンドが存在し得ない理由はありませんが、それを見つけることができなかったことに少し驚いています...


...だから作成しました!dlcallを使用すると、コマンドラインからライブラリ関数を呼び出すことができます

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

それは機能プロトタイプの限られたセットをサポートします、それは現在ひどく信頼性や弾力性はありませんが、それは現在存在しています。


たとえば Pythonおよびpython -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world を使用することもできますが、それは確かに最も簡単な方法ではありません。 Perl、Ruby、およびその他の言語には、使用できる同様の機能があります。


だからあなたの質問への答えは:

  1. 上記のいずれかの方法を使用します。
  2. あなたはdo別のコマンドを使用してbootstrapあなたをライブラリに入れるか、シェルにフックするソフトウェアの一部を使う必要があります。

全体として、他の方法でこれを行う方が確実に良いでしょう。

39
Michael Homer

aproposコマンドは多くの点で役立ちますが、多くの「ジャンク」も提供します。リストするもののほとんどはCライブラリルーチン(これは、マニュアルのセクション3が対象です)であり、シェルから直接使用することはできません。

それらを使用するには、それらを呼び出すCプログラムを作成する必要があります。これは、この特定のサイトでカバーされているトピックの範囲外です( StackOverflow のトピックにあります)。

したがって、これらはあなたの質問に対する答えです:

  1. できません。これらはCライブラリルーチンです。
  2. Cプログラムを書かない限りできません。

私はあなたがこれを知っていることを知っていますが、完全を期すために:シェルで、変数stringに文字列がある場合、次のようにすることができます

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

これにより、Length of string "hello world" is 1111から取得されるターミナルに${#string}が出力され、$stringの文字列の長さに展開されます。

内部的には、シェルは長さの計算を行うためにリストしたライブラリー呼び出しの1つを使用している可能性があります。

これは、シェルで、シェル変数に格納されている文字列の長さを取得する最も効率的な方法です。

${#string}POSIXシェルパラメータ展開 であることにも注意してください。したがって、ある程度のPOSIX準拠を主張するすべてのシェル間で移植可能です。

28
Kusalananda

strlen()だけでこれを行うことはしませんが、Cコードを試すのに役立つトリックです。

 user @ Host:〜$ gdb gdb 
(gdb)start 
一時ブレークポイント1、... in main()
(gdb)print strlen( " foob​​ar ")
 $ 1 = 6 

ここでgdbはGNUデバッガーであり、通常はその後にデバッグするためにプログラム名を必要とします。何もないため、この例ではデバッグするためにそれ自体を与えています。次にstartはプログラムを起動し、その後gdbを使用して任意のCコードを実行できます。

15
jpa

共有ライブラリの関数をインタラクティブに呼び出すために使用できるツール:「Witchcraftコンパイラコレクション」。 https://github.com/endrazine/wcc

GitHubページから:

wsh:Witchcraft Shell

Witchcraftシェルは、ELF共有ライブラリ、ELF ET_DYN実行可能ファイル、およびPunk-Cで記述されたWitchcraftシェルスクリプトを入力として受け入れます。すべての実行可能ファイルを独自のアドレス空間にロードし、そのAPIを組み込みインタープリターでプログラミングできるようにします。これにより、Javaなどの言語でのリフレクションを介して提供されるものと同様のバイナリ機能が提供されます。

wshの使用例次のコマンドは、wsh内の_/usr/sbin/Apache2_実行可能ファイルをロードし、Apache内のap_get_server_banner()関数を呼び出して取得しますバナーを表示し、wshインタープリター内に表示します。

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