shell腳本fork
⑴ shell腳本中調用腳本
裡面有個錯誤,time 是個命令,不能用來做變數,這是致命的!
----------------
我給個測試腳本你試一下:
.............
#!/bin/sh
flag=0
plan_hour=19
plan_minutes=47
plan_time=`echo -n "$plan_hour";echo -n "$plan_minutes"`
clear
while true
do
hour=`date +"%H"`
minutes=`date +"%M"`
seconds=`date +"%S"`
time1=`echo -n "$hour";echo -n "$minutes"`
clear
echo -n "現在的時間為: "
echo -n $hour
echo -n :
echo -n $minutes
echo -n :
echo -n $seconds
if [ "$time1" -eq "$plan_time" ]; then
flag=1
clear
echo -n "3秒後關閉 1.sh"
sleep 3
ps -ef|grep "sh 1.sh"|grep -v grep|awk '{print $2}'|xargs kill
clear
echo "1.sh 已經結束;2.sh 1分鍾後喚醒 1.sh"
sleep 59
fi
sleep 1
if [ $flag -eq 1 ]; then
sh 1.sh
exit 0
fi
done
===============
腳本一開始預定關閉 1.sh 的時間。
在未到定時時,就顯式時間。
定時時間到,給出殺死 1.sh 的提示,3秒後殺死,然後再 1 分鍾後再喚醒 1.sh 進程。喚醒 1.sh 後,2.sh 也就跟著退出了。
------------------------------------------------------
2.sh 時間設對了是可以殺死 1.sh 的。
如果按照你的要求,我覺得寫個程序應該更好處理些,參考代碼如下:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
int main()
{
pid_t pid;
while(1) {
pid = fork();
switch(pid) {
case -1:
perror("fork failed");
exit(1);
case 0:
while(1) {
printf("I'm 1.sh ,I'm running........\n");
sleep(1);
}
default:
sleep(5);
kill(pid, SIGKILL);
printf("child over\n");
sleep(40);
break;
}
}
return 0;
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
上面程序,先 fork() 出一個子進程,相當於 1.sh,然後你在子進程里做你要做的事情。父進程在 5s 後(相當於每天預設的一個時間,每天的時間設定可用相關的函數進行設置檢測)殺死子進程,然後睡眠 40s,醒來後,又循環 fork() 同樣的子進程做同樣的事情。
C程序調用shell腳本共同擁有三種法子 :system()、popen()、exec系列數call_exec1.c ,
system() 不用你自己去產生進程。它已經封裝了,直接增加自己的命令
exec 須要你自己 fork 進程,然後exec 自己的命令
popen() 也能夠實現運行你的命令,比system 開銷小
方法一、system()的使用。我直接上代碼吧
int system(const char *command);
我在/home/book/shell新建一個test.sh文件例如以下:
<span style="font-size:18px;"><span style="font-size:18px;">#!bin/bash
echo $HOME
echo "the is test!"</span></span>
test.c文件例如以下:
<span style="font-size:18px;"><span style="font-size:18px;">#include<stdlib.h>
int main()
{
system("bash /home/book/shell/test.sh"); /* chmod +x test.sh ,路徑前面要加上bash */
return 0;
}</span></span>
運行例如以下命令來編譯:
<span style="font-size:18px;">gcc test.c -o test
</span>
測試命令:
<span style="font-size:18px;">./test</span>
結果例如以下:
<span style="font-size:18px;">/root
the is test!</span>
方法二:popen() 會調用fork()產生 子歷程,然後從子歷程中調用/bin/sh -c來履行 參數command的指令。參數type可應用 「r」代表讀取。「w」代表寫入。遵循此type值。popen()會建立 管道連到子歷程的標准 輸出設備 或標准 輸入設備 ,然後返回一個文件指針。
隨後歷程便可利用 此文件指針來讀取子歷程的輸出設備 或是寫入到子歷程的標准 輸入設備 中。此外,全部應用 文 件指針(FILE*)操作的函數也都能夠應用 ,除了fclose()以外。
返回值:若成功 則返迴文件指針,否則返回NULL,差錯 原因存於errno中。注意:在編寫具SUID/SGID許可權的程序時請盡量避免應用 popen()。popen()會繼承環境變數。通過環境變數可能會造成系統安全的問題
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
其它不用改變我們直接改動test.c文件:
#include<stdio.h>
int main()
{
char buffer[80];
FILE *fp=popen("bash /home/book/shell/test.sh","r");
fgets(buffer,sizeof(buffer),fp);
printf("%s",buffer);
pclose(fp);
return 0;
}
方法三:exec函數簇 (我不太懂,別人的。也沒有驗證。習慣方法一)
須要注意的是exec並非1個函數, 事實上它僅僅是一組函數的統稱, 它包含以下6個函數:
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[];
能夠見到這6個函數名字不同, 並且他們用於接受的參數也不同.
實際上他們的功能都是幾乎相同的, 由於要用於接受不同的參數所以要用不同的名字區分它們, 畢竟c語言沒有函數重載的功能嘛..
可是實際上它們的命名是有規律的:
exec[l or v][p][e]
exec函數里的參數能夠分成3個部分, 運行文件部分, 命令參數部分, 環境變數部分.
比如我要運行1個命令 ls -l /home/gateman
運行文件部分就是 "/usr/bin/ls"
命令參賽部分就是 "ls","-l","/home/gateman",NULL 見到是以ls開頭 每1個空格都必須分開成2個部分, 並且以NULL結尾的啊.
環境變數部分, 這是1個數組,最後的元素必須是NULL 比如 char * env[] = {"PATH=/home/gateman", "USER=lei", "STATUS=testing", NULL};
好了說下命名規則:
e興許, 參數必須帶環境變數部分, 環境變零部分參數會成為運行exec函數期間的環境變數, 比較少用
l 興許, 命令參數部分必須以"," 相隔, 最後1個命令參數必須是NULL
v 興許, 命令參數部分必須是1個以NULL結尾的字元串指針數組的頭部指針. 比如char * pstr就是1個字元串的指針, char * pstr[] 就是數組了, 分別指向各個字元串.
關於Linux命令的介紹,看看《linux就該這么學》,具體關於這一章地址3w(dot)linuxprobe/chapter-02(dot)html
p興許, 運行文件部分能夠不帶路徑, exec函數會在$PATH中找
還有1個注意的是, exec函數會代替運行它的進程, 也就是說, 一旦exec函數運行成功, 它就不會返回了, 進程結束. 可是假設exec函數運行失敗, 它會返回失敗的信息, 並且進程繼續運行後面的代碼!
通常exec會放在fork() 函數的子進程部分, 來替代子進程運行啦, 運行成功後子程序就會消失, 可是運行失敗的話, 必須用exit()函數來讓子進程退出!
⑶ linux中fork,source和exec的區別
exec和source都屬於bash內部命令(builtins commands),在bash下輸入man exec或man source可以查看所有的內部命令信息。
bash shell的命令分為兩類:外部命令和內部命令。外部命令是通過系統調用或獨立的程序實現的,如sed、awk等等。內部命令是由特殊的文件格式(.def)所實現,如cd、history、exec等等。
在說明exec和source的區別之前,先說明一下fork的概念。
fork是linux的系統調用,用來創建子進程(child process)。子進程是父進程(parent process)的一個副本,從父進程那裡獲得一定的資源分配以及繼承父進程的環境。子進程與父進程唯一不同的地方在於pid(process id)。
環境變數(傳給子進程的變數,遺傳性是本地變數和環境變數的根本區別)只能單向從父進程傳給子進程襲臘。不管子進程的環境變數如何變化,都不會影響父進程的環境變數。
shell script:
有兩種方法執行shell scripts,一種是新產生一個shell,然後執行相應的shell scripts;一種是在當前shell下執行,不再啟用其他shell。
新產生一個shell然後再執行scripts的方法是在scripts文件開頭加入以下語句
#!/bin/sh
一般的script文件(.sh)即是這種用法。這種方法先啟用新的sub-shell(新的子進程),然後在其下執行命令。
另外一種方法就是上面說過的source命令,不再產生新的shell,而在當前shell下執行一切命令。
source:
source命令即點(.)命令。
在bash下輸入man source,找到source命拍沒滑令解釋處,可以看到解釋"Read and execute commands from filename in the current shell environment and ..."。從中可以知道,source命令是在當前進程中執行參數文件中的各個命令,而不是察銀另起子進程(或sub-shell)。source filename or .filename 執行filename中的命令。
exec:
在bash下輸入man exec,找到exec命令解釋處,可以看到有"No new process is created."這樣的解釋,這就是說exec命令不產生新的子進程。那麼exec與source的區別是什麼呢?
exec命令在執行時會把當前的shell process關閉,然後換到後面的命令繼續執行。
======================================================================================================================
下面我們寫個腳本來測試一下,這樣你就會很容易的讀懂我上面所說的東西~
1.sh
#!/bin/bashA=Becho"PIDfor1.shbeforeexec/source/fork:
"exportAecho"1.sh:$Ais$A"case$1inexec)echo"usingexec..."exec./2.sh;;source)echo"usingsource..."../2.sh;;∗)echo"usingforkbydefault..."./2.sh;;esacecho"PIDfor1.shafterexec/source/fork:
"echo"1.sh:$Ais$A"
2.sh
#!/bin/bash
echo"PIDfor2.sh:$$"
echo"2.shget$A=$Afrom1.sh"
A=C
exportA
echo"2.sh:$Ais$A"
=================》》》》》》》》》》》
測試結果:
[root@node2 ~]$ ./1.sh fork
PID for 1.sh before exec/source/fork:10175
1.sh: $A is B
using fork by default...
PID for 2.sh:10176
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:10175
1.sh: $A is B
=============================================
[root@node2 ~]$ ./1.sh source
PID for 1.sh before exec/source/fork:10185
1.sh: $A is B
using source...
PID for 2.sh:10185
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:10185
1.sh: $A is C
=============================================
[root@node2 ~]$ ./1.sh exec
PID for 1.sh before exec/source/fork:10194
1.sh: $A is B
using exec...
PID for 2.sh:10194
2.sh get $A=B from 1.sh
2.sh: $A is C
[cpsuser@cps-svr-153 zy]$
=============================================
從以上結果可以看出:
1.執行source和exec的過程中沒有產生新的進程,而fork是默認的運行方式,在運行的過程中會產生新的進程,也就是子進程
2.source和exec的區別在於exec執行完畢後沒有輸出進程,也就是說運行完畢2.sh後直接退出了,沒有返回1.sh
3.fork和source的最後一句輸出分別為:1.sh: $A is B (fork,說明它運行的環境不一樣,要不然輸出的應該是C)
1.sh: $A is C(source,說明從始至終都是在一個shell中執行)
小節:
source 指定腳本中的命令在同一個shell中運行。(默認shell中的命令都是創建sub-shell,然後執行。執行完後,返回父shell)
fork 就是創建sub-shell運行腳本中的命令,和默認運行方式相同。
exec 和source相似,區別就是,運行完畢命令後退出,不會返回父shell