粉絲提問:彭老師,問下,在程序里面執(zhí)行system("cd /某個目錄"),這樣會切換不成功,為啥呢
實例代碼:
粉絲的疑惑是明明第10行執(zhí)行了cd /media操作,為什么12行執(zhí)行的pwd > test2.txt結果提示的仍然是當前目錄?
這是一個很不錯的問題,要想整明白這個問題,需要知道system的原理。
system()函數(shù)
通過man手冊來查看system庫函數(shù):
由手冊可得:
- system()是庫函數(shù)通過fork()函數(shù)創(chuàng)建子進程在子進程中通過exec族函數(shù)執(zhí)行shell命令
這樣大家就明白了,實際上system執(zhí)行參數(shù)中的字符串代表的命令,
其實是創(chuàng)建了一個進程,然后在子進程中通過exec族函數(shù)來執(zhí)行對應的命令。
當前工作路徑,cwd,可以通過pwd來獲取,
那么工作路徑是和進程相關的,
第10行代碼執(zhí)行之后,雖然確實改變了此時的子進程的工作路徑,
但是隨著子進程的退出該工作路徑已沒有意義,
而執(zhí)行到12行程序的時候,system()又會創(chuàng)建新的子進程,
該子進程仍然繼承父進程的工作路徑,
所以當前工作路徑就沒有變化。
程序中如何修改當前程序的工作路徑?
可以通過函數(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ù)是個系統(tǒng)調用(system是庫函數(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
由結果可知,8行代碼修改了當前進程的工作路徑為根路徑,
所以第9行執(zhí)行l(wèi)s命令顯示的是根路徑下面的內容
驗證system()
下面我們來看一下,system()這個函數(shù)是如何調用系統(tǒng)調用的。
編寫測試函數(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?}
要想知道某個函數(shù)調用過程,最終調用到哪些系統(tǒng)調用函數(shù),可以借助strace命令
在Linux系統(tǒng)中,strace命令是一個集診斷、調試、統(tǒng)計與一體的工具,可用來追蹤調試程序,能夠與其他命令搭配使用
執(zhí)行結果:
由截圖可知,當我們運行程序時,首先會加載鏈接庫,以便于我們執(zhí)行當前程序,
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
最終調用到系統(tǒng)調用函數(shù)clone(),
clone(child_stack=0,?flags=CLONE_PARENT_SETTID|SIGCHLD,?parent_tidptr=0x7fffdff4b59c)?=?2753
并獲取到執(zhí)行結果
wait4(2753,?123.c??a.sh??basic??chat??chris??encryption??net??run??sgm3141?srand
但是前面說了,system不是調用fork的嗎?
man?clone
寫的很清楚了,clone與fork行為一致。
好了,本文就到這。