1. 關於 wait_event_interruptible() 和 wake_up()的使用
讀一下wait_event_interruptible()的源碼,不難發現這個函數先將
當前進程的狀態設置成TASK_INTERRUPTIBLE,然後調用schedule(),
而schedule()會將位於TASK_INTERRUPTIBLE狀態的當前進程從runqueue
隊列中刪除。從runqueue隊列中刪除的結果是,當前這個進程將不再參
與調度,除非通過其他函數將這個進程重新放入這個runqueue隊列中,
這就是wake_up()的作用了。
由於這一段代碼位於一個由condition控制的for(;;)循環中,所以當由
shedule()返回時(當然是被wake_up之後,通過其他進程的schedule()而
再次調度本進程),如果條件condition不滿足,本進程將自動再次被設
置為TASK_INTERRUPTIBLE狀態,接下來執行schedule()的結果是再次被
從runqueue隊列中刪除。這時候就需要再次通過wake_up重新添加到
runqueue隊列中。
如此反覆,直到condition為真的時候被wake_up.
可見,成功地喚醒一個被wait_event_interruptible()的進程,需要滿足:
在 1)condition為真的前提下,2) 調用wake_up()。
所以,如果你僅僅修改condition,那麼只是滿足其中一個條件,這個時候,
被wait_event_interruptible()起來的進程尚未位於runqueue隊列中,因
此不會被 schedule。這個時候只要wake_up一下就立刻會重新進入運行調度。
2. 關於wait_event_interruptible的返回值
根據 wait_event_interruptible 的宏定義知:
1) 條件condition為真時調用這個函數將直接返回0,而當前進程不會
被 wait_event_interruptible和從runqueue隊列中刪除。
2) 如果要被wait_event_interruptible的當前進程有nonblocked pending
signals, 那麼會直接返回-ERESTARTSYS(i.e. -512),當前進程不會
被wait_event_interruptible 和從runqueue隊列中刪除。
3) 其他情況下,當前進程會被正常的wait_event_interruptible,並從
runqueue隊列中刪除,進入TASK_INTERRUPTIBLE狀態退出運行調度,
直到再次被喚醒加入runqueue隊列中後而參與調度,將正常返回0。
附1:wait_event_interruptible 宏
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) \
__wait_event_interruptible(wq, condition, __ret); \
__ret; \
})
註: C語言中{a,b, ..., x}的的值等於最後一項,即x,因此上述
宏的值是 __ret。
附2:wait_event_interruptible()和 wake_up的等效代碼
wait_event_interruptible(wq, condition) /*等效沒有考慮返回值*/
{
if (!(condition))
{
wait_queue_t _ _wait;
init_waitqueue_entry(&_ _wait, current);
add_wait_queue(&wq, &_ _wait);
for (;;)
{
set_current_state(TASK_INTERRUPTIBLE);
if (condition)
break;
schedule(); /* implicit call: del_from_runqueue(current)*/
}
current->state = TASK_RUNNING;
remove_wait_queue(&wq, &_ _wait);
}
}
void wake_up(wait_queue_head_t *q)
{
struct list_head *tmp;
wait_queue_t *curr;
list_for_each(tmp, &q->task_list)
{
curr = list_entry(tmp, wait_queue_t, task_list);
wake_up_process(curr->task);
/* implicit call: add_to_runqueue(curr->task);*/
if (curr->flags)
break;
}
}
2014年11月6日 星期四
[轉] add_timer的使用方法
add_timer的使用方法
首先你要申請一個timer struct:
static struct timer_list timer;
或是用pointer申請
static struct timer_list *timer;
在第一次使用時一定要初始化:
init_timer(&timer);
設定要傳的data
timer.data = (unsigned long )foo_data;
設定間隔時間
timer.expires = jiffies + DELAY_TIME;
設定timer到時要跑的function
timer.function = foo_function;
接著把這個timer加進timer list結構
add_timer(&timer);
時間到了就會跳起來去執行程式foo_function,
但是從此timer不會再跳起來,必須重新add_timer才會在下一次繼續啟動
在離開時,記得要
del_timer(&timer);
static struct timer_list timer;
或是用pointer申請
static struct timer_list *timer;
在第一次使用時一定要初始化:
init_timer(&timer);
設定要傳的data
timer.data = (unsigned long )foo_data;
設定間隔時間
timer.expires = jiffies + DELAY_TIME;
設定timer到時要跑的function
timer.function = foo_function;
接著把這個timer加進timer list結構
add_timer(&timer);
時間到了就會跳起來去執行程式foo_function,
但是從此timer不會再跳起來,必須重新add_timer才會在下一次繼續啟動
在離開時,記得要
del_timer(&timer);
[轉] Linux Kernel: 簡介HZ, tick and jiffies
Linux核心幾個重要跟時間有關的名詞或變數,底下將介紹HZ、tick與jiffies。
HZ
Linux核心每隔固定週期會發出timer interrupt (IRQ 0),HZ是用來定義每一秒有幾次timer interrupts。舉例來說,HZ為1000,代表每秒有1000次timer interrupts。HZ可在編譯核心時設定,如下所示 (以核心版本2.6.20-15為例):
其中HZ可設定100、250、300或1000。以小弟的核心版本預設值為250。
小實驗
觀察/proc/interrupt的timer中斷次數,並於一秒後再次觀察其值。理論上,兩者應該相差250左右。
問題來了,timer interrupt會做哪些事情? 答案如下所列:
Tick是HZ的倒數,意即timer interrupt每發生一次中斷的時間。如HZ為250時,tick為4毫秒 (millisecond)。
Jiffies
Jiffies為Linux核心變數(32位元變數,unsigned long),它被用來紀錄系統自開幾以來,已經過多少的tick。每發生一次timer interrupt,Jiffies變數會被加一。值得注意的是,Jiffies於系統開機時,並非初始化成零,而是被設為-300*HZ (arch/i386/kernel/time.c),即代表系統於開機五分鐘後,jiffies便會溢位。那溢位怎麼辦? 事實上,Linux核心定義幾個macro(timer_after、time_after_eq、time_before與time_before_eq),即便是溢位,也能藉由這幾個macro正確地取得jiffies的內容。
另外,80x86架構定義一個與jiffies相關的變數jiffies_64 ,此變數64位元,要等到此變數溢位可能要好幾百萬年。因此要等到溢位這刻發生應該很難吧。那如何經由jiffies_64取得jiffies資訊呢? 事實上,jiffies被對應至jiffies_64最低的32位元。因此,經由jiffies_64可以完全不理會溢位的問題便能取得jiffies。
HZ
Linux核心每隔固定週期會發出timer interrupt (IRQ 0),HZ是用來定義每一秒有幾次timer interrupts。舉例來說,HZ為1000,代表每秒有1000次timer interrupts。HZ可在編譯核心時設定,如下所示 (以核心版本2.6.20-15為例):
adrian@adrian-desktop:~$ cd /usr/src/linux
adrian@adrian-desktop:/usr/src/linux$ make menuconfig
Processor type and features ---> Timer frequency (250 HZ) --->
其中HZ可設定100、250、300或1000。以小弟的核心版本預設值為250。
小實驗
觀察/proc/interrupt的timer中斷次數,並於一秒後再次觀察其值。理論上,兩者應該相差250左右。
adrian@adrian-desktop:~$ cat /proc/interrupts | grep timer && sleep 1 && cat /proc/interrupts | grep timer
0: 9309306 IO-APIC-edge timer
0: 9309562 IO-APIC-edge timer
上面四個欄位分別為中斷號碼、CPU中斷次數、PIC與裝置名稱。問題來了,timer interrupt會做哪些事情? 答案如下所列:
- 更新時間、日期與系統從開機至目前經過多少時間 。
- 更新系統資源使用率統計
- 檢查正在執行的程序是否已經超過其所分配的執行時間額度。如果是的話,則侵佔(preempt)該程序以利執行其它等待執行的程序。
- 檢查軟體時間器(Software timer,如alarm系統呼叫)跟時間延遲函式(Delay function)的延遲時間是否已經超過。
Tick是HZ的倒數,意即timer interrupt每發生一次中斷的時間。如HZ為250時,tick為4毫秒 (millisecond)。
Jiffies
Jiffies為Linux核心變數(32位元變數,unsigned long),它被用來紀錄系統自開幾以來,已經過多少的tick。每發生一次timer interrupt,Jiffies變數會被加一。值得注意的是,Jiffies於系統開機時,並非初始化成零,而是被設為-300*HZ (arch/i386/kernel/time.c),即代表系統於開機五分鐘後,jiffies便會溢位。那溢位怎麼辦? 事實上,Linux核心定義幾個macro(timer_after、time_after_eq、time_before與time_before_eq),即便是溢位,也能藉由這幾個macro正確地取得jiffies的內容。
另外,80x86架構定義一個與jiffies相關的變數jiffies_64 ,此變數64位元,要等到此變數溢位可能要好幾百萬年。因此要等到溢位這刻發生應該很難吧。那如何經由jiffies_64取得jiffies資訊呢? 事實上,jiffies被對應至jiffies_64最低的32位元。因此,經由jiffies_64可以完全不理會溢位的問題便能取得jiffies。
2014年11月5日 星期三
[轉] Using GCC to create static and shared library
Library可分成三種,static、shared與dynamically loaded。
1. Static libraries
Static 程式庫用於靜態連結,簡單講是把一堆object檔用ar(archiver)包裝集合起來,檔名以 `.a' 結尾。優點是執行效能通常會比後兩者快,
而且因為是靜態連結,所以不易發生執行時找不到library或版本錯置而
無法執行的問題。缺點則是檔案較大,維護度較低;例如library如果發
現bug需要更新,那麼就必須重新連結執行檔。
1.1 編譯
編譯方式很簡單,先例用 `-c' 編出 object 檔,再用 ar 包起來即可。
____ hello.c ____
#include <stdio.h>
void hello(){ printf("Hello "); }
____ world.c ____
#include <stdio.h>
void world(){ printf("world."); }
____ mylib.h ____
void hello();
void world();
$ gcc -c hello.c world.c /* 編出 hello.o 與 world.o */
$ ar rcs libmylib.a hello.o world.o /* 包成 limylib.a */
這樣就可以建出一個檔名為 libmylib.a 的檔。輸出的檔名其實沒有硬性規定,
但如果想要配合 gcc 的 '-l' 參數來連結,一定要以 `lib' 開頭,中間是你要
的library名稱,然後緊接著 `.a' 結尾。
1.2 使用
____ main.c ____
#include "mylib.h"
int main() {
hello();
world();
}
使用上就像與一般的 object 檔連結沒有差別。
$ gcc main.c libmylib.a
也可以配合 gcc 的 `-l' 參數使用
$ gcc main.c -L. -lmylib
`-Ldir' 參數用來指定要搜尋程式庫的目錄,`.' 表示搜尋現在所在的目錄。
通常預設會搜 /usr/lib 或 /lib 等目錄。
`-llibrary' 參數用來指定要連結的程式庫 ,'mylib' 表示要與mylib進行連結
,他會搜尋library名稱前加`lib'後接`.a'的檔案來連結。
$ ./a.out
Hello world.
2. Shared libraries
Shared library 會在程式執行起始時才被自動載入。因為程式庫與執行檔
是分離的,所以維護彈性較好。有兩點要注意,shared library是在程式起始
時就要被載入,而不是執行中用到才載入,而且在連結階段需要有該程式庫
才能進行連結。
首先有一些名詞要弄懂,soname、real name與linker name。
soname 用來表示是一個特定 library 的名稱,像是 libmylib.so.1 。
前面以 `lib' 開頭,接著是該 library 的名稱,然後是 `.so' ,接著
是版號,用來表名他的介面;如果介面改變時,就會增加版號來維護相容度。
real name 是實際放有library程式的檔案名稱,後面會再加上 minor 版號與
release 版號,像是 libmylib.so.1.0.0 。
一般來說,版號的改變規則是(印象中在 APress-Difinitive Guide to GCC中有
提到,但目前手邊沒這本書),最尾碼的release版號用於程式內容的修正,
介面完全沒有改變。中間的minor用於有新增加介面,但相舊介面沒改變,所以
與舊版本相容。最前面的version版號用於原介面有移除或改變,與舊版不相容
時。
linker name是用於連結時的名稱,是不含版號的 soname ,如: libmylib.so。
通常 linker name與 real name是用 ln 指到對應的 real name ,用來提供
彈性與維護性。
1. Static libraries
Static 程式庫用於靜態連結,簡單講是把一堆object檔用ar(archiver)包裝集合起來,檔名以 `.a' 結尾。優點是執行效能通常會比後兩者快,
而且因為是靜態連結,所以不易發生執行時找不到library或版本錯置而
無法執行的問題。缺點則是檔案較大,維護度較低;例如library如果發
現bug需要更新,那麼就必須重新連結執行檔。
1.1 編譯
編譯方式很簡單,先例用 `-c' 編出 object 檔,再用 ar 包起來即可。
____ hello.c ____
#include <stdio.h>
void hello(){ printf("Hello "); }
____ world.c ____
#include <stdio.h>
void world(){ printf("world."); }
____ mylib.h ____
void hello();
void world();
$ gcc -c hello.c world.c /* 編出 hello.o 與 world.o */
$ ar rcs libmylib.a hello.o world.o /* 包成 limylib.a */
這樣就可以建出一個檔名為 libmylib.a 的檔。輸出的檔名其實沒有硬性規定,
但如果想要配合 gcc 的 '-l' 參數來連結,一定要以 `lib' 開頭,中間是你要
的library名稱,然後緊接著 `.a' 結尾。
1.2 使用
____ main.c ____
#include "mylib.h"
int main() {
hello();
world();
}
使用上就像與一般的 object 檔連結沒有差別。
$ gcc main.c libmylib.a
也可以配合 gcc 的 `-l' 參數使用
$ gcc main.c -L. -lmylib
`-Ldir' 參數用來指定要搜尋程式庫的目錄,`.' 表示搜尋現在所在的目錄。
通常預設會搜 /usr/lib 或 /lib 等目錄。
`-llibrary' 參數用來指定要連結的程式庫 ,'mylib' 表示要與mylib進行連結
,他會搜尋library名稱前加`lib'後接`.a'的檔案來連結。
$ ./a.out
Hello world.
2. Shared libraries
Shared library 會在程式執行起始時才被自動載入。因為程式庫與執行檔
是分離的,所以維護彈性較好。有兩點要注意,shared library是在程式起始
時就要被載入,而不是執行中用到才載入,而且在連結階段需要有該程式庫
才能進行連結。
首先有一些名詞要弄懂,soname、real name與linker name。
soname 用來表示是一個特定 library 的名稱,像是 libmylib.so.1 。
前面以 `lib' 開頭,接著是該 library 的名稱,然後是 `.so' ,接著
是版號,用來表名他的介面;如果介面改變時,就會增加版號來維護相容度。
real name 是實際放有library程式的檔案名稱,後面會再加上 minor 版號與
release 版號,像是 libmylib.so.1.0.0 。
一般來說,版號的改變規則是(印象中在 APress-Difinitive Guide to GCC中有
提到,但目前手邊沒這本書),最尾碼的release版號用於程式內容的修正,
介面完全沒有改變。中間的minor用於有新增加介面,但相舊介面沒改變,所以
與舊版本相容。最前面的version版號用於原介面有移除或改變,與舊版不相容
時。
linker name是用於連結時的名稱,是不含版號的 soname ,如: libmylib.so。
通常 linker name與 real name是用 ln 指到對應的 real name ,用來提供
彈性與維護性。
2.1 編譯
shared library的製作過程較複雜。
$ gcc -c -fPIC hello.c world.c
編譯時要加上 -fPIC 用來產生 position-independent code。也可以用 -fpic參數。 (不太清楚差異,只知道 -fPIC 較通用於不同平台,但產生的code較大
,而且編譯速度較慢)。
$ gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 \
hello.o world.o
-shared 表示要編譯成 shared library
-Wl 用於參遞參數給linker,因此-soname與libmylib.so.1會被傳給linker處理。
-soname用來指名 soname 為 limylib.so.1
library會被輸出成libmylib.so.1.0.0 (也就是real name)
若不指定 soname 的話,在編譯結連後的執行檔會以連時的library檔名為
soname,並載入他。否則是載入soname指定的library檔案。
可以利用 objdump 來看 library 的 soname。
$ objdump -p libmylib.so | grep SONAME
SONAME libmylib.so.1
若不指名-soname參數的話,則library不會有這個欄位資料。
在編譯後再用 ln 來建立 soname 與 linker name 兩個檔案。
$ ln -s libmylib.so.1.0.0 libmylib.so
$ ln -s libmylib.so.1.0.0 libmylib.so.1
2.2 使用
與使用 static library 同。
$ gcc main.c libmylib.so
以上直接指定與 libmylib.so 連結。
或用
$ gcc main.c -L. -lmylib
linker會搜尋 libmylib.so 來進行連結。
如果目錄下同時有static與shared library的話,會以shared為主。
使用 -static 參數可以避免使用shared連結。
$ gcc main.c -static -L. -lmylib
此時可以用 ldd 看編譯出的執行檔與shared程式庫的相依性
$ldd a.out
linux-gate.so.1 => (0xffffe000)
libmylib.so.1 => not found
libc.so.6 => /lib/libc.so.6 (0xb7dd6000)
/lib/ld-linux.so.2 (0xb7f07000)輸出結果顯示出該執行檔需要 libmylib.so.1 這個shared library。
會顯示 not found 因為沒指定該library所在的目錄,所找不到該library。
因為編譯時有指定-soname參數為 libmylib.so.1 的關係,所以該執行檔會
載入libmylib.so.1。否則以libmylib.so連結,執行檔則會變成要求載入
libmylib.so
$ ./a.out
./a.out: error while loading shared libraries: libmylib.so.1:
cannot open shared object file: No such file or directory
因為找不到 libmylib.so.1 所以無法執行程式。
有幾個方式可以處理。
a. 把 libmylib.so.1 安裝到系統的library目錄,如/usr/lib下
b. 設定 /etc/ld.so.conf ,加入一個新的library搜尋目錄,並執行ldconfig更新快取
c. 設定 LD_LIBRARY_PATH 環境變數來搜尋library這個例子是加入目前的目錄來搜尋要載作的library
$ LD_LIBRARY_PATH=. ./a.out
Hello world.
shared library的製作過程較複雜。
$ gcc -c -fPIC hello.c world.c
編譯時要加上 -fPIC 用來產生 position-independent code。也可以用 -fpic參數。 (不太清楚差異,只知道 -fPIC 較通用於不同平台,但產生的code較大
,而且編譯速度較慢)。
$ gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 \
hello.o world.o
-shared 表示要編譯成 shared library
-Wl 用於參遞參數給linker,因此-soname與libmylib.so.1會被傳給linker處理。
-soname用來指名 soname 為 limylib.so.1
library會被輸出成libmylib.so.1.0.0 (也就是real name)
若不指定 soname 的話,在編譯結連後的執行檔會以連時的library檔名為
soname,並載入他。否則是載入soname指定的library檔案。
可以利用 objdump 來看 library 的 soname。
$ objdump -p libmylib.so | grep SONAME
SONAME libmylib.so.1
若不指名-soname參數的話,則library不會有這個欄位資料。
在編譯後再用 ln 來建立 soname 與 linker name 兩個檔案。
$ ln -s libmylib.so.1.0.0 libmylib.so
$ ln -s libmylib.so.1.0.0 libmylib.so.1
2.2 使用
與使用 static library 同。
$ gcc main.c libmylib.so
以上直接指定與 libmylib.so 連結。
或用
$ gcc main.c -L. -lmylib
linker會搜尋 libmylib.so 來進行連結。
如果目錄下同時有static與shared library的話,會以shared為主。
使用 -static 參數可以避免使用shared連結。
$ gcc main.c -static -L. -lmylib
此時可以用 ldd 看編譯出的執行檔與shared程式庫的相依性
$ldd a.out
linux-gate.so.1 => (0xffffe000)
libmylib.so.1 => not found
libc.so.6 => /lib/libc.so.6 (0xb7dd6000)
/lib/ld-linux.so.2 (0xb7f07000)輸出結果顯示出該執行檔需要 libmylib.so.1 這個shared library。
會顯示 not found 因為沒指定該library所在的目錄,所找不到該library。
因為編譯時有指定-soname參數為 libmylib.so.1 的關係,所以該執行檔會
載入libmylib.so.1。否則以libmylib.so連結,執行檔則會變成要求載入
libmylib.so
$ ./a.out
./a.out: error while loading shared libraries: libmylib.so.1:
cannot open shared object file: No such file or directory
因為找不到 libmylib.so.1 所以無法執行程式。
有幾個方式可以處理。
a. 把 libmylib.so.1 安裝到系統的library目錄,如/usr/lib下
b. 設定 /etc/ld.so.conf ,加入一個新的library搜尋目錄,並執行ldconfig更新快取
c. 設定 LD_LIBRARY_PATH 環境變數來搜尋library這個例子是加入目前的目錄來搜尋要載作的library
$ LD_LIBRARY_PATH=. ./a.out
Hello world.
3. Dynamically loaded libraries
Dynamicaaly loaded libraries 才是像 windows 所用的 DLL ,在使用到
時才載入,編譯連結時不需要相關的library。動態載入庫常被用於像plug-ins的應用。
3.1 使用方式
動態載入是透過一套 dl function來處理。
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);開啟載入 filename 指定的 library。
void *dlsym(void *handle, const char *symbol);取得 symbol 指定的symbol name在library被載入的記憶體位址。
int dlclose(void *handle);關閉dlopen開啟的handle。
char *dlerror(void);傳回最近所發生的錯誤訊息。
____ dltest.c ____
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main() {
void *handle;
void (*f)();
char *error;
/* 開啟之前所撰寫的 libmylib.so 程式庫 */
handle = dlopen("./libmylib.so", RTLD_LAZY);
if( !handle ) {
fputs( dlerror(), stderr);
exit(1);
}
/* 取得 hello function 的 address */
f = dlsym(handle, "hello");
if(( error=dlerror())!=NULL) {
fputs(error, stderr);
exit(1);
}
/* 呼叫該 function */
f();
dlclose(handle);
}
編譯時要加上 -ldl 參數來與 dl library 連結
$ gcc dltest.c -ldl結果會印出 Hello 字串
$ ./a.out
Hello
關於dl的詳細內容請參閱 man dlopen
Dynamicaaly loaded libraries 才是像 windows 所用的 DLL ,在使用到
時才載入,編譯連結時不需要相關的library。動態載入庫常被用於像plug-ins的應用。
3.1 使用方式
動態載入是透過一套 dl function來處理。
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);開啟載入 filename 指定的 library。
void *dlsym(void *handle, const char *symbol);取得 symbol 指定的symbol name在library被載入的記憶體位址。
int dlclose(void *handle);關閉dlopen開啟的handle。
char *dlerror(void);傳回最近所發生的錯誤訊息。
____ dltest.c ____
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main() {
void *handle;
void (*f)();
char *error;
/* 開啟之前所撰寫的 libmylib.so 程式庫 */
handle = dlopen("./libmylib.so", RTLD_LAZY);
if( !handle ) {
fputs( dlerror(), stderr);
exit(1);
}
/* 取得 hello function 的 address */
f = dlsym(handle, "hello");
if(( error=dlerror())!=NULL) {
fputs(error, stderr);
exit(1);
}
/* 呼叫該 function */
f();
dlclose(handle);
}
編譯時要加上 -ldl 參數來與 dl library 連結
$ gcc dltest.c -ldl結果會印出 Hello 字串
$ ./a.out
Hello
關於dl的詳細內容請參閱 man dlopen
2014年11月4日 星期二
2014年11月3日 星期一
[轉] nohup: 讓command在遠端執行, 不因登出而中斷
對於寫程式的人,有些時候程式要跑得比較久,但是因為下班等原因必須關閉連線(不管是telnet或SSH)時,nohup就是你的好朋友!又或者你利用wget抓取一些需要好幾小時才能抓完的檔案時,你也可以利用nohup來幫祝你在離線後繼續抓取。
nohup是什麼?
nohup是由兩個字組成的命令:no-hup,hup指的是SIGHUP(hangup)這個信號,nohup就是忽略SIGHUP這個信號的意思。當我們從一個連線登出的時候,每個process都會收到一個SIGHUP信號,透過nohup所下達的命令就可以不受影響,繼續執行。
nohup如何使用?
nohup最傳統的用法就是在你要執行的命令之前加上nohup,然後在後面加上一個背景執行的 &,像這樣:
| $ nohup your_command & $ |
所有執行產生的輸出,將自動導出到nohup.txt。你也可以參考我之前的文章:
Linux Shell IO redirect (資料流重導向)
將輸出重新導出到新的檔案,例如myout.txt:
| $ nohup your_command &>myout.txt & $ |
察看nohup執行結果
一旦透過nohup執行命令,所有的輸出都會存到檔案,而不是直接顯示在螢幕上。如果你想要看執行結果的話,你可以用 tail 命令加上 -f 參數,讓shell自動為你在檔案有所更新時一併印出,也就是說看起來就好像你在看螢幕上的執行結果一樣:
| $ tail –f nohup.txt |
訂閱:
文章 (Atom)