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


27

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

$ 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 -mexpr lengthおよび他の回避策を知っています

しかし、私はここに2つの質問があります:

  1. どのように使用する任意のlibrary calls (3)シェル内部を?
  2. 他のコマンドではなく、ライブラリ呼び出しだけを使用して文字列の長さを計算する方法は?

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



4
基本的に、マイケルの答えは素晴らしいハックですが、簡単な答えはそうではありません。ライブラリー呼び出しはシェルに関連していません。C言語でプログラムを作成するために使用されます。- manページを読むとき、あなたがプログラムをコーディングしている場合を除きより一般的には、、、ただ無視するセクション2、3、9
spectras

トピック外ですが、OpenVMSには、多くのシステムライブラリ関数へのシェルインターフェイスである「字句」関数があります。
ロンジョン

回答:


39

あなたはおそらく これを行うべきではありませんが、できます。Kusalanandaの答えは、当面のタスクにとってより適切であり、問​​題を説明しています。ただし、ターミナル内でライブラリ呼び出しを使用する方法を具体的に尋ねたので、ここにいくつかの方法があります...


タイニーCコンパイラは、( tcc)をサポート-runフラグあなたはので、(実際に)あなたをすることができます小さなプログラムを書くことでCコードを解釈できるというの単一の呼び出しを介して端末内の任意のライブラリの呼び出しを使用しています。

次の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になるようにここでました-異なるアリティと戻り値の型ごとに個別の関数が必要になります)。


別のオプションは、Bashのプラグイン包み込むタビス・オーマンデイすることにより、および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やをpython -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world使用することもできますが、これを実行するのが最も簡単な方法ではないことは確かです。Perl、Ruby、および他の言語には、使用できる類似の機能があります。


あなたの質問に対する答えは次のとおりです。

  1. 上記のアプローチのいずれかを使用します。
  2. あなたがやるライブラリにあなたをブートストラップする別のコマンドを使用する必要がある、またはソフトウェアの一部あなたのシェルにフックいます。

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


2
「dlcall」は、Windowsの「rundll」(まったく同一ではない)を思い出させます:support.microsoft.com/en-gb/help/164787/…–
pjc50

1
@ pjc50:公共サービスの発表:rundll32は、任意の関数を呼び出すための汎用ツールではありません。指定された署名を持つ関数を呼び出すためにのみ使用できます。また、それはひどく将来性がない
ケビン

29

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ます。

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

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

あまりにも注意${#string}ですPOSIXシェルパラメータ展開、それはPOSIX準拠の任意の程度を主張するすべてのシェルの間のでポータブルです。


ライブラリ関数に関する部分は良い説明ですが、この答えの残りは少し誤解を招くかもしれません。OPは、「文字列の長さを単純に計算したかった」と言いprintfます。ここで使用する必要はありません。文の一部として印刷したい場合は、それが最善の方法かもしれません。しかし、「文字列の長さを取得するにはどうすればよいですか?」という質問に対する答えは ある${#string}部分ではなく、printf関数。あなただけのことができますecho ${#string}あなただけの長さだけ出力したい、または別の変数に割り当てた場合string_length=${#string}、あなたがしたいか、何でも。printfは実際には関係ありません
アダム

1
@Adam私は答えに小さな修正を加えました。文字列の長さを取得する方法はかなり明確だと思いますし、ユーザーはすでにそれを行う方法を知っていると言っています。文字列の長さを使用することで、printf「use ${#string}」と言う以外の何かを追加します(例から自明です)。
クサラナナンダ

15

私はただこれをやらない strlen()が、Cコードをときどき試すのに役立つトリックです。

user @ host:〜$ gdb gdb
(gdb)開始
main()の一時的なブレークポイント1、...
(gdb)strlen( "foobar")を出力します
$ 1 = 6

gdbGNUデバッガーを次に示します。通常は、デバッグ後にプログラム名を使用します。存在しないため、この例ではデバッグすることができます。次にstart、プログラムを起動し、その後、gdb任意のCコードを実行するために使用できます。


2
ナイストリック、gdbを使用する。ただし、gdbは開発者ツールの一部であり、ライブラリ関数を使用する場合は、開発者ツールの使用方法を学習する準備を整える必要があります。
デュディボーイ

4

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

GitHubページから:

wsh:Witchcraftシェル

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

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

jonathan@blackbox:~$ wsh /usr/sbin/apache2
> a = ap_get_server_banner()
> print(a)
Apache/2.4.7
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.