2010年3月17日 星期三

大量改檔名

若同一個資料夾裡,要用同樣的規則修改檔名,如所有為.dat副檔名要更名為.txt,可以寫一個簡單的shell script來完成。

先了解變數替換的方法
${var%word} - 由var變數內容的後端,向前刪除符合word關鍵字(最短部份)
${var%%word} - 由var變數內容的後端,向前刪除符合word關鍵字(最長份)
${var#word} - 由var變數內容的前端,向後刪除符合word關鍵字(最短部份)
${var##word} - 由var變數內容的前端,向後刪除符合word關鍵字(最長部份)

舉例:
變數$abc = howard, john, tom
# echo ${abc%,*}
howard, john
# echo ${abc%%,*}
howard

重新命名範例:將附檔名dat改為txt
#/bin/bash
for i in *.dat
do
mv $i "${i%dat}txt"
done

2010年3月14日 星期日

strtok in C++

C++來實作類似strtok()的function

class StrTok : public vector<std::string> {
public:
StrTok(const string & strInput, const string & strDelim = " ,") {
string::size_type nHead, nTail;
nHead = strInput.find_first_not_of(strDelim, 0);
nTail = strInput.find_first_of(strDelim, nHead);

while(nHead != string::npos || nTail != string::npos) {
push_back(strInput.substr(nHead, nTail - nHead));
nHead = strInput.find_first_not_of(strDelim, nTail);
nTail = strInput.find_first_of(strDelim, nHead);
}
}
};

兩個參數,第一個參數為預切割的字串,第二個參數為切割的符號(預設為逗號),因為是繼承vector,所以可以直接用vector的function去存取切割後的字串。範例如下:

StrTok tok("howard, john");
for(StrTok::size_type i = 0; i < tok.size(); i++)
cout << tok[i];

2010年3月11日 星期四

MySQL最大連線數

MySQL的最大連線數可以透過my.cnf設定檔來設定

max_connections = 200 (若沒有設定,預設值為100)。

上述方法需重新啟動MySQL才能套用設定,另一種方法則是直接下指令,缺點就是下次重啟動時還是會回到原設定
mysql> set global max_connections = 200;

透過以下指來可查看此參數設定。
mysql> show variables;

至於目前的連線數,可透過Threads_connected來得知,動態變化,可透過以下指令得知目前連線數
mysql> show status;

此外,若發現MySQL的連線數出現異常,如短時間爆增連線,可以用以下指令來找尋目前的連線狀態,找出當下SQL Query的指令與來源。
mysql> show full processlist;

若有異常的指令,可以下kill來刪除該指令
mysql> kill [id]

2010年3月7日 星期日

命令執行

在Shell Script常常會需要抓取或是儲存執行某個指令的結果。舊式的寫法是用反引號`cmd`,要注意的一點就是符號不是單引號(')。而新式的寫法是採用$(cmd)。

舊式:
echo The current date is `date`

新式
echo The current date is $(date)

F2 重新命名

在Windows作業系統,在圖示按兩下便可以更改檔名,然而在Linux下的桌面環境,點兩下卻是沒有回應,要按右鍵屬性去修改,感覺有些麻煩。現在才發現有一個更快的方法,那就是F2鍵就如同在圖示點兩下,Windows也適用。

2010年2月20日 星期六

網頁轉址

常常忘記語法,先記下來。
<meta http-equiv="refresh" content="0; url=xxx.html">

2010年1月3日 星期日

Daemon Tutorial

參考一份文件,介紹寫Daemon程式所需要的基本步驟:
1. Fork off the parent process
利用fork()脫離父程序,成為init的子程序
2. Change file mode mask
利用umask()控制Daemon所建立的檔案權限
3. Open any logs for writing
可透過寫檔或是syslog來記錄執行的過程
4. Create a unique Session ID
利用setsid()建立新的session並脫離tty
5. Change the current working directory to a safe place
利用chdir()來改變工作目錄(用意不太清楚)
6. Close standard file descriptors
因為Daemon不會使用terminal,所以關閉不必要的descriptors
7. Enter actual daemon code
Daemon所要執行的程式

程式碼架構可參考此網站
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>

#define DAEMON_NAME "MyDaemon"

int main(int argc, char** argv)
{
pid_t pid, sid;

// Change file mode mask
umask(0);

// Open logs for writing
openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_USER);
syslog(LOG_NOTICE, "%s daemon started", DAEMON_NAME);

pid = fork();
if(pid < 0) {
syslog(LOG_ERR, "Fail to fork a process");
exit(EXIT_FAILURE);
}

// Fork off the parent process
if(pid > 0) {
exit(EXIT_SUCCESS);
}

// Create a unique Session ID
sid = setsid();
if(sid < 0) {
syslog(LOG_ERR, "Fail to create a new Session ID");
exit(EXIT_FAILURE);
}

// Change the current working directory
if((chdir("/") < 0)) {
syslog(LOG_ERR, "Fail to change the current working directory");
exit(EXIT_FAILURE);
}

// Close out the standard file descriptiors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);

//******************************************************************
// Insert the daemon process
//******************************************************************

exit(EXIT_SUCCESS);
}

2009年12月17日 星期四

格式化輸出

今天在寫Shell script時,需要用到格式化輸出,例如要串接001~100,可以用for迴圈加上printf達成:

for number in $(seq 1 100)
do
format=`printf %.03d $number`
# Do something else
done

2009年12月12日 星期六

Pipe

當兩個不同的Process要溝通時,我們可以用pipe來達成。簡單來說,pipe就像是一條水管,連接兩個Process,其中一端寫入資料到水管,另一端便可從水管中讀出此資料。

建立pipe:
#include <unistd.h>
int pipe(int pipefd[2]);

呼叫pipe()來建立pipe,其參數int pipefd[2]是用來回傳兩個file descriptors,pipefd[0]代表的是pipe的讀取端,pipefd[1]則是pipe的寫入端。

簡單範例:
#include <stdio.h>
#include <string.h>

int main() {
int pipefd[2];
pipe(pipefd);

char writeBuf[] = "Hello pipe!";
write(pipefd[1], writeBuf, strlen(writeBuf));

char readBuf[20];
int n = read(pipefd[0], readBuf, 20);
readBuf[n] = 0;
printf("%s\n", readBuf);

return 0;
}

接下來就將單一Process擴展到不同的Process,寫出ls | wc -l,也就是計算當前目錄下有幾個檔案。
先利用fork產生Child Process,再叫用execlp()執行外部指令。

#include <stdio.h>
#include <unistd.h>

int main() {
int pipefd[2];
pipe(pipefd);

pid_t pid = fork();
if(pid != 0) {
close(pipefd[1]);
dup2(pipefd[0], 0);
close(pipefd[0]);
execlp("wc", "wc", "-l", NULL);
}
else {
close(pipefd[0]);
dup2(pipefd[1], 1);
close(pipefd[1]);

execlp("ls", "ls", NULL);
}
return 0;
}

由於fork會使pipefd[0], pipefd[1]產生兩份,記得把不必要的Descriptor關閉,可避免不當的操作。
比較需要注意的便是dup2()的用法,dup2(pipefd[0], 0)可以把它想成複製pipefd[0]且當作是標準輸入(stdin),如此wc -l從stdin讀資料就會從pipe中讀取。
可參考此網頁的說明,便能明白dup2()的用意。

2009年12月9日 星期三

freopen()

當我們想要redirect我們的標準輸出(stdout)或標準輸入(stdin)到某一個檔案,可以使用freopen()來達成。
FILE *freopen(const char *path, const char *mode, FILE *stream);

以下是簡單小範例

#include <iostream>
int main() {
freopen("test.txt", "w", stdout);
std::cout << "Hello freopen()" << std::endl;
return 0;
}


執行時,便不會看到任何輸出,而是會出現在test.txt檔案裡。