쉘에서 라이브러리 명령을 실행하는 방법은 무엇입니까?


27

단순히 문자열의 길이 (해시 값)를 계산하고 싶었습니다. 그래서 터미널을 열고 이것을했습니다 :

$ apropos length

그것은 끝에 명령 또는 기능이 (3)있거나 (3ssl)추가 된 많은 명령 / 기능으로 나를 반환 했습니다. 이제 man man 은 이러한 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다른 해결 방법을.

그러나 여기에 두 가지 질문이 있습니다.

  1. 어떻게 사용하는 모든library calls (3) 쉘 내부를?
  2. 다른 명령이 아닌 라이브러리 호출을 사용하여 문자열 길이를 계산하는 방법은 무엇입니까?

참고 : 질문은 일반적으로 library calls쉘에서의 사용법에 중점을 둡니다 . 따라서 첫 번째 질문에 답하는 것이 더 중요합니다.



4
기본적으로 Michael의 대답은 대단한 해킹이지만 간단한 대답은 아닙니다. 라이브러리 호출은 쉘과 관련 이 없습니다 . C 언어로 프로그램을 작성하는 데 사용됩니다. —보다 일반적으로, 맨 페이지를 읽을 때 프로그램을 코딩하지 않는 한 섹션 2, 3 및 9를 무시하십시오.
Spectras

Off Topic이지만 OpenVMS에는 많은 시스템 라이브러리 함수에 대한 셸 인터페이스 인 "어휘"기능이 있습니다.
RonJohn

답변:


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하여 읽을 파일을 제공 하여 모든 파일의 결과를 포함하는 것으로 보입니다 echo. 다른 옵션이 있습니다.

이것을 생성하는 기능을 만들 수 있습니다.

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여기서는 단항 함수 문자열이되도록 사용 했습니다-> int-각 arity 및 return 유형마다 별도의 함수가 필요합니다).


또 다른 옵션은 배쉬 플러그인 래핑으로 알려졌다 의해 와 . 이것은 아마도 당신이 시도한 것에 가장 가까운 근사치 일 것입니다. 예를 들어 다음을 사용할 수 있습니다.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는 임의의 함수를 호출하기위한 범용 도구아닙니다 . 주어진 서명으로 함수를 호출하는 데만 사용할 수 있습니다. 또한 미래에 대한 증거는 아닙니다 .
Kevin

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 11터미널에서 인쇄 됩니다 .11${#string}$string

내부적으로 쉘은 길이 계산을 위해 나열된 라이브러리 호출 중 하나를 사용하고있을 수 있습니다.

이것은 쉘에서 쉘 변수에 저장된 문자열의 길이를 얻는 가장 효율적인 방법입니다.

너무 주 ${#string}이다 는 POSIX 쉘 매개 변수 확장 , 그것은 POSIX 준수의 정도를 주장하는 모든 쉘 사이 따라서 휴대용이다.


라이브러리 함수에 대한 부분은 좋은 설명이지만이 답변의 나머지 부분은 약간 오해의 소지가 있습니다. OP는 "단순히 문자열의 길이를 계산하고 싶었다" 고 말합니다 printf. 여기서 사용할 필요는 없습니다 . 문장의 일부로 인쇄하려면 가장 좋은 방법 일 수 있습니다. 그러나 "줄 길이는 어떻게 얻습니까?"라는 질문에 대한 대답 는 IS ${#string}부분이 아닌 printf와. echo ${#string}길이 만 출력 string_length=${#string}하거나 원하는 다른 변수를 다른 변수에 할당하려는 경우 에만 가능합니다 . printf는 실제로 관련이 없습니다
Adam

1
@Adam 나는 대답을 약간 수정했습니다. 나는 문자열의 길이를 얻는 방법이 매우 분명하다고 생각하며 사용자는 이미 문자열을 사용하는 방법을 알고 있다고 말했습니다. 문자열 길이 를 사용 하여 printf"use ${#string}" 라고 말하는 것 이외의 다른 것을 추가합니다 (이 예제에서는 자명합니다).
Kusalananda

15

나는 이것을 위해 이것을하지 않을 strlen()것이지만 때로는 C 코드를 시험해 볼 때 유용한 트릭입니다.

user @ host : ~ $ gdb gdb
(gdb) 시작
메인의 임시 중단 점 1 ...
(gdb) 인쇄 strlen ( "foobar")
$ 1 = 6

여기 gdb에 GNU 디버거가 있으며 일반적으로 디버깅을 위해 프로그램 이름이 필요합니다. 우리는 아무것도 없기 때문에이 예제는 스스로 디버깅을 제공합니다. 그런 다음 start프로그램을 시작한 후 gdb임의의 C 코드를 실행하는 데 사용할 수 있습니다.


2
gdb를 사용하는 좋은 트릭. 그러나 gdb는 개발자 도구의 일부이므로 라이브러리 기능을 사용하려면 개발자 도구 사용 방법을 배우는 것이 좋습니다.
Dudi Boy

4

공유 라이브러리에서 "Witchcraft Compiler Collection"이라는 대화 형 함수를 대화식으로 호출하는 데 사용할 수있는 도구입니다. https://github.com/endrazine/wcc

GitHub 페이지에서 :

wsh : 마법의 껍질

witchcraft 쉘은 ELF 공유 라이브러리, ELF ET_DYN 실행 파일 및 Punk-C로 작성된 Witchcraft 셸 스크립트를 입력으로 허용합니다. 모든 실행 파일을 자체 주소 공간에로드하고 API를 내장 된 인터프리터에서 프로그래밍 할 수 있도록합니다. 이는 Java와 같은 언어에서 리플렉션을 통해 제공되는 것과 유사한 이진 기능을 제공합니다.

wsh 사용법 예제 다음 명령 은 wsh/usr/sbin/apache2 내에 실행 파일을 로드하고 ap_get_server_banner()아파치 내의 함수를 호출하여 배너를 검색하여 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.