Linux에서 ls를 실행하면 어떤 시스템 호출이 발생합니까?
Linux에서는 ls를 실행하면 읽기 및 exec 시스템 호출이 발생합니다. 쉘 명령을 실행하면 fork 및 exec가 호출되지만 strace를 사용하여 ls로 인한 시스템 호출을 확인하면 ls 명령이 파일을 나열하지 않습니다. 디렉토리에 있으므로 read가 호출됩니다.
이 튜토리얼의 운영 환경: linux7.3 시스템, Dell G3 컴퓨터.
Linux에서 ls를 실행하면 어떤 시스템 호출이 발생할까요
답은 읽기 및 실행 시리즈입니다
셸 명령 실행 메커니즘은 fork+exec이고, fork는 복제, execve는 변환입니다. ls 명령은 디렉터리의 파일을 나열하므로 read도 호출됩니다.
fork 및 exec 명령을 통해 Linux 커널에 대한 쉘 액세스가 가능합니다. 동일한 스레드에서 생성할 수 있습니다.
strace를 사용하여 ls로 인한 시스템 호출을 확인하세요. 포크가 없는 것은 사실이지만 어떤 쉘 명령을 실행하면 포크가 호출되기 때문입니다
execve의 변형은 새로운 프로세스를 생성하고 교체하는 것입니다. 새 프로세스로 원래 프로세스를 삭제합니다.
먼저 시스템 호출이 무엇인지 논의해 볼까요?
사용자는 UNIX/Linux에서 직접 제공하는 소수의 기능을 이용하여 파일 및 장치에 접근하고 제어할 수 있습니다. 이러한 기능이 시스템 호출
[1]입니다. 系统调用
[1]。
使用strace ls
命令我们可以查看ls命令使用到的系统调用[2],其中一部分输出内容如下:
open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3 getdents64(3, /* 68 entries */, 32768) = 2240 getdents64(3, /* 0 entries */, 32768) = 0 close(3) = 0
open系统调用打开当前目录文件,返回获得的文件描述符。可以看到该文件使用O_RDONLY标志打开。
只要该文件是用O_RDONLY或O_RDWR标志打开的,就可以用read()
系统调用从该文件中读取字节[3]。
所以ls
要用到read
系统调用。除此之外,任何shell命令都会创建进程,都会用到exec系统调用。
回过头来梳理一下我们对于这些概念可能产生的疑惑:
- 包括ls在内,一个程序是如何运行的?
- open系统调用打开当前目录文件,返回获得的文件描述符。那什么是文件描述符?
1 进程是如何运行的
每个运行中的程序被称为进程[1]
Unix将进程创建与加载一个新进程映象分离。这样的好处是有更多的余地对两种操作进行管理。当我们创建了一个进程之后,通常将子进程替换成新的进程映象。所以任何shell命令都会创建进程,都会用到exec系统调用。
例如:在shell命令行执行ps命令,实际上是shell进程调用fork复制一个新的子进程,在利用exec系统调用将新产生的子进程完全替换成ps进程。
用exec函数可以把当前进程替换为一个新进程,且新进程与原进程有相同的PID。exec名下是由多个关联函数组成的一个完整系列[4]
调用fork创建新进程后,父进程与子进程几乎一模一样[1,p398]。
fork是一个UNIX术语,当fork一个进程(一个运行中的程序)时,基本上是复制了它,并且fork后的两个进程都从当前执行点继续运行,并且每个进程都有自己的内存副本。
原进程是父进程,新进程是子进程。可以通过fork()
strace ls
명령을 사용하면 ls 명령[2]에서 사용되는 시스템 호출을 볼 수 있습니다. 출력의 일부는 다음과 같습니다.
#include<unistd.h> #include<stdio.h> #define LEN 10 int main() { pid_t id=getpid(); printf("Main pid: %d \n",id); int i; pid_t res=fork(); if(res==0) { for(i =0;i<LEN;i++) { pid_t id1=getpid(); printf("%d ",id1); printf("Child process:%d\n",i); } } else { printf("res %d\n",res); for(i=0;i<LEN;i++) { pid_t id2=getpid(); printf("%d ",id2); printf("parent process:%d\n",i); } } printf("THE END\n"); return 0; } /*output Main pid: 10965 res 10966 10965 parent process:0 10965 parent process:1 10965 parent process:2 10965 parent process:3 10965 parent process:4 10965 parent process:5 10965 parent process:6 10965 parent process:7 10965 parent process:8 10965 parent process:9 10966 Child process:0 10966 Child process:1 THE END 10966 Child process:2 10966 Child process:3 10966 Child process:4 10966 Child process:5 10966 Child process:6 10966 Child process:7 10966 Child process:8 10966 Child process:9 THE END */
read()
시스템 호출[3]을 사용하여 파일에서 바이트를 읽을 수 있습니다. 그래서 ls
는 read
시스템 호출을 사용해야 합니다. 또한 프로세스를 생성하는 모든 쉘 명령은 exec 시스템 호출을 사용합니다. 다시 돌아가 이러한 개념에 대해 우리가 가질 수 있는 의심을 정리해 보겠습니다. - ls를 포함하여 프로그램은 어떻게 실행됩니까?
- open 시스템 호출은 현재 디렉터리에서 파일을 열고 얻은 파일 설명자를 반환합니다. 그렇다면 파일 설명자는 무엇입니까?
예를 들어 쉘 명령줄에서 ps 명령을 실행하면 쉘 프로세스는 실제로 새로운 하위 프로세스를 복사하기 위해 포크를 호출한 다음 exec 시스템 호출을 사용하여 새로 생성된 하위 프로세스를 ps 프로세스로 완전히 대체합니다.
🎜exec 기능을 사용하여 현재 프로세스를 새 프로세스로 교체하면 새 프로세스는 원래 프로세스와 동일한 PID를 갖습니다. exec라는 이름 아래에는 여러 관련 함수로 구성된 완전한 시리즈가 있습니다[4]🎜🎜fork를 호출하여 새 프로세스를 생성한 후 상위 프로세스와 하위 프로세스는 거의 동일합니다[1, p398]. 🎜🎜fork는 UNIX 용어로 프로세스(실행 중인 프로그램)가 Fork되면 기본적으로 복사되며, Fork 이후의 두 프로세스는 모두 현재 실행 지점부터 계속 실행되며 각 프로세스는 고유한 메모리 복사본을 갖습니다. 🎜🎜원래 프로세스는 상위 프로세스이고 새 프로세스는 하위 프로세스입니다.fork()
의 반환 값으로 구별할 수 있습니다. 🎜🎜🎜부모 프로세스의 포크 호출은 새 자식 프로세스의 pid(프로세스 ID)를 반환하고, 자식 프로세스의 포크 호출은 0🎜🎜🎜을 반환합니다. 예: 🎜#include<string.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include<unistd.h> char command[256]; void main() { int rtn; /*子进程的返回数值*/ while(1) { /* 从终端读取要执行的命令 */ printf( ">" ); fgets( command, 256, stdin ); command[strlen(command)-1] = 0; if ( fork() == 0 ) {/* 子进程执行此命令 */ execlp( command, NULL ); /* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/ perror( command ); exit( errno ); } else {/* 父进程, 等待子进程结束,并打印子进程的返回值 */ pid_t sonid=wait ( &rtn ); printf(" child pid: %d\n",sonid); printf( " child process return %d\n", rtn ); } } } /*output:错误命令、需要参数命令、正确命令 >aa aa: No such file or directory child pid: 11230 child process return 512 >echo A NULL argv[0] was passed through an exec system call. child pid: 11231 child process return 134 >ps child pid: 11247 child process return 139 */
#include<unistd.h> ssize_t read(int filedes, void *buf, size_t nbytes);
对内核而言,所有打开的文件都通过文件描述符引用[7]。文件描述符是非负整数,范围是[0,OPEN_MAX -1]。现在OPEN_MAX 一般为64
但是[7]又说对于FreeBSD 8.0,Linux 3.2.0 ,Mac OS X 10.6.8等, fd变化范围几乎无限,只受到存储器数量、int字长以及系统管理员所配置的软限制和硬限制的约束。。。why?
当open或者create一个新文件时,内核向进程返回一个文件描述符。
当读、写一个文件时,使用open或create返回的文件描述符标识该文件,将其作为参数传送给read / write
按照惯例,fd为0 / 1 / 2分别关联STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO。这些常量也定义在unistd.h
.
3 系统调用包含在哪些头文件中呢?
包括exec、fork、read、write在内,许多系统调用包含在unistd.h
头文件中
POSIX,Portable Operating System Interface。是UNIX系统的一个设计标准,很多类UNIX系统也在支持兼容这个标准,如Linux。unistd.h
是POSIX标准定义的unix类系统定义符号常量的头文件,包含了许多UNIX系统服务的函数原型[5]。在该头文件,用于访问设备驱动程序的底层函数(系统调用)有这五个:open/close/read/write/ioctl
[1]。
4 文件I/O
[7]中提到大多数文件I/O用到的5个函数为:open/read/write/lseek/close
4.1 函数read
调用read函数从打开文件中读数据。
#include<unistd.h> ssize_t read(int filedes, void *buf, size_t nbytes);
返回值:
成功,读出的字节数;
失败,-1;
遇到文件尾,0
有多种情况可使实际读到的字节数少于要求读的字节数:
- 读普通文件时,在读到要求字节数之前已经到达了文件尾端。
例如,若在到达文件尾端之前还有30个字节,而要求读100个字节,则read返回30,下一次再调用read时,它将回0。
当从终端设备读时,通常一次最多读一行
当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
当从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么read将只返回实际可用的字节数。
当从某些面向记录的设备(例如磁盘)读时,一次最多返回一个记录。
当某一信号造成中断,而已经读了部分数据量时。读操作从文件的当前偏移量出开始,在成功返回之前,该偏移量将增加实际独到的字节数
read的经典原型定义则是:
int read(int fd, char*buf, unsigned nbytes);
相关推荐:《Linux视频教程》
위 내용은 Linux에서 ls를 실행하면 어떤 시스템 호출이 발생합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











대 코드 시스템 요구 사항 : 운영 체제 : Windows 10 이상, MacOS 10.12 이상, Linux 배포 프로세서 : 최소 1.6GHz, 권장 2.0GHz 이상의 메모리 : 최소 512MB, 권장 4GB 이상의 저장 공간 : 최소 250MB, 권장 1GB 및 기타 요구 사항 : 안정 네트워크 연결, Xorg/Wayland (LINUX)

메모장은 Java 코드를 직접 실행할 수는 없지만 다른 도구를 사용하여 명령 줄 컴파일러 (Javac)를 사용하여 Bytecode 파일 (filename.class)을 생성하면 달성 할 수 있습니다. Java Interpreter (Java)를 사용하여 바이트 코드를 해석하고 코드를 실행하고 결과를 출력하십시오.

VS 코드 확장을 설치하는 이유는 다음과 같습니다. 네트워크 불안정성, 불충분 한 권한, 시스템 호환성 문제, C 코드 버전은 너무 오래된, 바이러스 백신 소프트웨어 또는 방화벽 간섭입니다. 네트워크 연결, 권한, 로그 파일, 업데이트 대 코드 업데이트, 보안 소프트웨어 비활성화 및 대 코드 또는 컴퓨터를 다시 시작하면 점차 문제를 해결하고 해결할 수 있습니다.

Linux 시스템의 5 가지 기본 구성 요소는 다음과 같습니다. 1. Kernel, 2. System Library, 3. System Utilities, 4. 그래픽 사용자 인터페이스, 5. 응용 프로그램. 커널은 하드웨어 리소스를 관리하고 시스템 라이브러리는 사전 컴파일 된 기능을 제공하며 시스템 유틸리티는 시스템 관리에 사용되며 GUI는 시각적 상호 작용을 제공하며 응용 프로그램은 이러한 구성 요소를 사용하여 기능을 구현합니다.

VS 코드는 Mac에서 사용할 수 있습니다. 강력한 확장, GIT 통합, 터미널 및 디버거가 있으며 풍부한 설정 옵션도 제공합니다. 그러나 특히 대규모 프로젝트 또는 고도로 전문적인 개발의 경우 VS 코드는 성능 또는 기능 제한을 가질 수 있습니다.

VS Code는 Full Name Visual Studio Code로, Microsoft가 개발 한 무료 및 오픈 소스 크로스 플랫폼 코드 편집기 및 개발 환경입니다. 광범위한 프로그래밍 언어를 지원하고 구문 강조 표시, 코드 자동 완료, 코드 스 니펫 및 스마트 프롬프트를 제공하여 개발 효율성을 향상시킵니다. 풍부한 확장 생태계를 통해 사용자는 디버거, 코드 서식 도구 및 GIT 통합과 같은 특정 요구 및 언어에 확장을 추가 할 수 있습니다. VS 코드에는 코드에서 버그를 신속하게 찾아서 해결하는 데 도움이되는 직관적 인 디버거도 포함되어 있습니다.

Visual Studio Code (VSCODE)는 Microsoft가 개발 한 크로스 플랫폼, 오픈 소스 및 무료 코드 편집기입니다. 광범위한 프로그래밍 언어에 대한 가볍고 확장 성 및 지원으로 유명합니다. VSCODE를 설치하려면 공식 웹 사이트를 방문하여 설치 프로그램을 다운로드하고 실행하십시오. VScode를 사용하는 경우 새 프로젝트를 만들고 코드 편집, 디버그 코드, 프로젝트 탐색, VSCODE 확장 및 설정을 관리 할 수 있습니다. VSCODE는 Windows, MacOS 및 Linux에서 사용할 수 있으며 여러 프로그래밍 언어를 지원하며 Marketplace를 통해 다양한 확장을 제공합니다. 이점은 경량, 확장 성, 광범위한 언어 지원, 풍부한 기능 및 버전이 포함됩니다.

git 저장소 주소를 보려면 다음 단계를 수행하십시오. 1. 명령 줄을 열고 리포지토리 디렉토리로 이동하십시오. 2. "git remote -v"명령을 실행하십시오. 3. 출력 및 해당 주소에서 저장소 이름을 봅니다.
