粉絲提問:
彭老師,問下,在程序里面執(zhí)行system("cd /某個(gè)目錄"),這樣會(huì)切換不成功,為啥呢
實(shí)例代碼:
粉絲的疑惑是明明第10行執(zhí)行了cd /media操作, 為什么12行執(zhí)行的pwd > test2.txt結(jié)果提示的仍然是當(dāng)前目錄?
這是一個(gè)很不錯(cuò)的問題,要想整明白這個(gè)問題,需要知道system的原理。
system()函數(shù)
通過(guò)man手冊(cè)來(lái)查看system庫(kù)函數(shù):
由手冊(cè)可得:
- system()是庫(kù)函數(shù)
- 通過(guò)fork()函數(shù)創(chuàng)建子進(jìn)程
- 在子進(jìn)程中通過(guò)exec族函數(shù)執(zhí)行shell命令
這樣大家就明白了,實(shí)際上system執(zhí)行參數(shù)中的字符串代表的命令, 其實(shí)是創(chuàng)建了一個(gè)進(jìn)程,然后在子進(jìn)程中通過(guò)exec族函數(shù)來(lái)執(zhí)行對(duì)應(yīng)的命令。
當(dāng)前工作路徑,cwd,可以通過(guò)pwd來(lái)獲取,
那么工作路徑是和進(jìn)程相關(guān)的,
第10行代碼執(zhí)行之后,雖然確實(shí)改變了此時(shí)的子進(jìn)程的工作路徑,
但是隨著子進(jìn)程的退出該工作路徑已沒有意義,
而執(zhí)行到12行程序的時(shí)候,system()又會(huì)創(chuàng)建新的子進(jìn)程,
該子進(jìn)程仍然繼承父進(jìn)程的工作路徑,
所以當(dāng)前工作路徑就沒有變化。
程序中如何修改當(dāng)前程序的工作路徑?
可以通過(guò)函數(shù)chdir()
CHDIR(2) linux Programmer's Manual CHDIR(2)
NAME
chdir, fchdir - change working directory
SYNOPSIS
#include <unistd.h>
int chdir(const char *path);
int fchdir(int fd);
Feature Test macro Requirements for glibc (see feature_test_macros(7)):
fchdir():
_BSD_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
DESCRIPTION
chdir() changes the current working directory of the calling process to the directory specified in path.
fchdir() is identical to chdir(); the only difference is that the directory is given as an open file descriptor.
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set Appropriately.
該函數(shù)是個(gè)系統(tǒng)調(diào)用(system是庫(kù)函數(shù))。
代碼舉例:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 int main(int argc, char **argv)
6 {
7 system("ls");
8 chdir("/");
9 system("ls");
10 return 0;
11 }
peng@ubuntu:~/test$ ./run
123.c a.sh basic chat chris encryption .NET run sgm3141 srand
app boot dev home initrd.img.old lib32 libx32 media opt root sbin srv tftpboot usr vmlinuz www
bin cdrom etc initrd.img lib lib64 lost+found mnt proc run snap sys tmp var vmlinuz.old
由結(jié)果可知,8行代碼修改了當(dāng)前進(jìn)程的工作路徑為根路徑, 所以第9行執(zhí)行l(wèi)s命令顯示的是根路徑下面的內(nèi)容
驗(yàn)證system()
下面我們來(lái)看一下,system()這個(gè)函數(shù)是如何調(diào)用系統(tǒng)調(diào)用的。
編寫測(cè)試函數(shù)
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(int argc, char **argv)
5 {
6 system("ls");
7 return 0;
8 }
要想知道某個(gè)函數(shù)調(diào)用過(guò)程,最終調(diào)用到哪些系統(tǒng)調(diào)用函數(shù),可以借助strace命令
在Linux系統(tǒng)中,strace命令是一個(gè)集診斷、調(diào)試、統(tǒng)計(jì)與一體的工具,可用來(lái)追蹤調(diào)試程序,能夠與其他命令搭配使用
執(zhí)行結(jié)果:
由截圖可知, 當(dāng)我們運(yùn)行程序時(shí),首先會(huì)加載鏈接庫(kù),以便于我們執(zhí)行當(dāng)前程序,
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
最終調(diào)用到系統(tǒng)調(diào)用函數(shù)clone(),
clone(child_stack=0, flags=CLONE_PARENT_SETTID|SIGCHLD, parent_tidptr=0x7fffdff4b59c) = 2753
并獲取到執(zhí)行結(jié)果
wait4(2753, 123.c a.sh basic chat chris encryption net run sgm3141 srand
但是前面說(shuō)了,system不是調(diào)用fork的嗎?
man clone
寫的很清楚了,clone與fork行為一致。






