2014年7月17日 星期四

[PHP] Laravel 更改路徑 - public 目錄


裝好 Laravel 後會發現,要打上localhost/MAMP/project_name/public/才會show出歡迎頁面
因為Laravel希望你將 Root 指向 public 目錄,避免網站核心被惡意存取
但現在希望把public這曾拿掉,url看起來才會輕鬆一點
要達到這樣的目的,我們要搬動3個檔案然後修改2行code就可!!

首先移到./public目錄下把.htaccess, index.php, favicon.ico移到外面
(與app, bootstrap, public, vendor資料夾同一層)
下一步
打開index.php修改兩個路徑
require __DIR__.'/../bootstrap/autoload.php';
$app = require_once __DIR__.'/../bootstrap/start.php';
//改成以下
require __DIR__.'/bootstrap/autoload.php';
$app = require_once __DIR__.'/bootstrap/start.php';
//其實就是把路徑調整而已 讓他抓對地方
Bingo DONE!

[PHP] Laravel 入坑 - 安裝設定


最近參加PHP社群活動認識了Laravel這套framework
一聽之下很有Ruby的影子
似乎就是我在尋覓的PHP framework
立馬來實作看看!!!!
Laravel使用Composer作為套件管理工具
所以就用Composer來把Laravel建置起來吧!
先確認Composer已經建置好
composer -v
有的繼續往下
沒得快去裝吧->我之前的文章"[PHP] Composer 建置"有教,快轉台過去裝
step by step.
cd ./[Project Location]  //移到專案要建置的位址
composer create-project laravel/laravel [Project Name] --prefer-dist  
//這步就會幫你把Laravel該有的都建起來!!
題外話補充: 在裝起來的過程中可能會遇到一些問題
像是最後出現error: mcrypt is required
然後就是建置failed的概念.....
有兩個可能原因
1. mcrypt並未安裝,解法如下
brew install php55-mcrypt
2. 如果使用的是MAMP之類在local端開發,那可能是php的PATH指定錯誤,解法如下
which php  #查哪個途徑的php正在被使用
           #理論上會出現這個錯誤,多數是使用中的php是指向的問題
cd ~       #先移動到home directory
vim .bash_profile  #編輯.bash_profile 加入以下資訊
export PATH=/Applications/MAMP/bin/php/php5.4.10/bin:$PATH
#記得先查一下MAMP目前用什麼version的php
重啟terminal,在看which php就能解決問題了,這時候再重新creat-project laravel一次就沒問題了!
run完出現以下資訊就代表Laravel project建好了!連key都幫你生好並設定好了: )

打開project資料夾可以看見一大包都已經裝好

之後主要會寫到的大致都在app/下的models, views, controllers和routes.php
但首先我們先針對config作一些初始設定(雖然Laravel官方說明他們不需要什麼建制就可以快速開發)
但還是來做些設定比較方便之後辦事
1. 因為Laravel非常好心的已經幫我們分好local, testing, packages三種開發階段,並會依不同階段的config去覆寫global的config
所以我們到./bootstrap/start.php找到etectEnvironment(),設定local端
hostname  #先查local端的name
$env = $app->detectEnvironment(array(

 'local' => array('homestead'),   //把homestead用hostname查回來的name取代掉

));
接著去查current application environment
php artisan env  #檢查目前專案的環境是哪個
#理論上取代後current application environment會從production -變成-> local
這邊大家會好奇 artisan是什麼指令呢?!
artisan直譯: 工匠,也就是官方主張的像工匠般藝術的coding !!!
在使用Laravel時,artisan是個很重要的指令,不管裝package, 建migration都需要透過它
php artisan [任務]  //使用artisan的標準格式
php artisan        //list出有哪些任務可使用
最後去./app/config/下的app.php和database.php做些timezone, sql的設定就可以做後續開發了!!
enjoy Laravel : )

2014年5月3日 星期六

[C/C++] Static 成員 概念和使用

在使用類別時可以同時生成各個物件時,物件會擁有相同的資料成員
其中有些屬性是共通不需要改變的
例如,寫遊戲時用一個類別專門產生 A 怪物,類別內設定 A 怪物出生地為“神秘洞穴”
當遊戲在大量生成怪物時,不用每隻怪都產生自己的“出生地”資料成員,因為都一樣
所以其實共用“出生地=神秘洞穴”這個資料成員可以達到節省記憶體目的
將資料成員宣告為 static ,被宣告為 static 的資料成員,它是屬於類別所擁有
而不是個別的物件,我們可以將 static 視為個別物件所擁有、共享的資料成員
把可共用的設定成 static 成員,不會造成每次類別生物件,每個資料成員都要複製一次,減少記憶體資源
宣告 static function -->封裝,別份檔案不能呼叫該 function
static 可允許不生成物件,直接利用 class member 或 function
class A
{
public:
 static int data1 ; // static 資料成員,各物件共用 data1
 int data2 ;

 static void setData1() //跟宣告 static 全域變數一樣可達到“封裝”,別份檔案無法呼叫此 function
 {                      //宣告為 static 的成員變數得用 static 的成員函數 ( member function )
  data1 = 77 ;
 }
 void setData2()
 {
  data2 = 500;
 }
};
記得在類別定義外先初始化 static 成員
順便生成一個 a1 物件,方便後面了解記憶體位置
class A
{
...
};

int A::data1 ;
A a1;

int main()
{
...
}
直接存取 static 成員變數
A::data1 = 99;
不生成物件,直接用類別名稱呼叫 static member function
A::setData1();
也可在生成物件之後,以物件名稱加上 '.' 運算子來存取 static 靜態資料成員,但是這個方式不被鼓勵
通常建議使用類別名稱加上 '::' 運算子來存取,一方面也可以避免與非靜態資料成員混淆
a1.data1; /**/
嘗試修改 a1 的 data1 和 data2 成員內容,
a1.setData2();
a1.data1 = 77; //再度強調,這存取 static 成員的方法應避免,應使用 A::data1,這邊僅為練習用
編譯結果,可以看見 data2 被修改成 500,而 data1 因共用關係
記憶體位置與類別下的 A::data1 一樣, A::data1 內容也從 99 改成 77

static 其他功用
用在 local variable -->(改變)增加生命期,讓原有的 scope 結束後,繼續存在到程式結束
用在 global variable -->把 scope 限制在該份 .cpp 檔裡,別份檔不能 link 到他-->封裝

2014年4月23日 星期三

[演算法]淺談 排序 (cont.)

int main()
{
 int arr[] = {1,5,2,6,7,8,9,4,10,14,52,99,47,100,199,222222,11,23};
 int length = sizeof(arr)/sizeof(int);

 cout << "before selection sort:" << endl;
 for(int i=0; i < length; i++)
  cout << arr[i] << " ";
 cout << endl;
 insertionSort(arr, length);
 //selectionSort(arr, length);
 //bubbleSort(arr, length);
 //quickSort(arr, 0, length);
 cout << "after selection sort:" << endl;
 for(int i=0; i < length; i++)
  cout << arr[i] << " ";
 cout << endl;
 system("pause");
 return 0;
}
先處理swapfunction
void swap(int* a, int* b) {
 int temp = *a;
 *a = *b;
 *b = temp;
}

氣泡排序法(Bubble sort)
void bubbleSort(int* arr, int length)
{
  for(int i=0; i < length-1; i++) {
   for(int j=1; j < length; j++) {
    if(arr[j-1] > arr[j]) {
     swap( &arr[j-1], &arr[j] );
    } else
     continue;
   }
  }
}
插入排序法(Insertion sort)
void insertionSort(int* arr, int length)
{
 for(int i=1; i<length; i++) {
  int temp = arr[i], index = i;
  for(int j=i-1; j>=0 && arr[j] > temp; j--) {
   arr[j+1] = arr[j];
   index = j;
  }
  arr[index] = temp;
 }
}
選擇排序法(Selection sort)
void selectionSort(int* arr, int length)
{
 for(int i=0; i<length; i++) {
  int index = i, min=arr[i];
  for(int j=i+1; j<length; j++) {
   if(arr[j] < min) {
    index = j;
    min=arr[j];
   }
  }
  if(index != i)
   swap(&arr[i], &arr[index]);
 }
}
快速排序法(Quick sort)
void quickSort(int* arr, int left, int right)
{
 int lpt, rpt, pvt;
 if( left < right ) {
  lpt = left + 1;
  rpt = right;
  pvt = arr[left];
  while( lpt <= rpt ) {
   while( arr[lpt] < pvt )
    lpt++;
   while( arr[rpt] > pvt )
    rpt--;
   if( lpt < rpt )
    swap( &arr[lpt], &arr[rpt] );
  }
   swap( &arr[left], &arr[rpt] );
   for(int p=0; p<sizeof(arr)/sizeof(int); p++)
    printf("sorting:%d\n",arr[p]);
   printf("\n");
   quickSort( arr, left, rpt-1 );
   quickSort( arr, rpt+1, right);
 }
}

2014年4月20日 星期日

[PHP] Composer 建置


如何在mac上建好composer這個利器呢!?
首先mac上要先有Homebrew這套mac的套件管理工具
沒有的要先裝好Homebrew(其實也可以用curl來裝,官網上有作法)
brew -v
#如果出現 Homebrew 0.X.X就代表成功嚕!
接著就利用brew指令來裝好composer吧
brew update

brew tap homebrew/homebrew-php

brew tap homebrew/dupes

brew tap homebrew/versions

brew install php55-intl

brew install homebrew/php/composer  #把composer裝下去!!


run完後
composer -v

















Bingo!!Composer裝好嚕
可以看到list出一堆可用的指令
ex.
create-project  #之後建置Laravel project時用到

update          #管理package和更新專案所用package時用到

...等 都是以後常用的指令!

至於怎麼找package、在專案裡加入package和使用package
之後的文章應該會提到
或直接到網站上了解一下吧!

2014年3月31日 星期一

[git]本機端與Github連結

git的認證是採用ssh金鑰進行,
要將本機端和Github做連結,得生出一組ssh金鑰才行,
把public key交給Github,private key留本機端,
等兩邊連結時金鑰配對成功,就可進行資料互換,金鑰如何設定,很簡單

Step 1. 先確認本機端是否已存在ssh key
-->打開terminal
cd ~/.ssh
ls -al
# 將.ssh資料夾內所有檔案列出來(含屬性與隱藏檔)
檢查是否有id_rsa.pub和id_dsa.pub 2個檔案,
理論上沒有,所以現在才要做生金鑰的工作啊(茶,

Step 2. 生金鑰
ssh-keygen -t rsa -C "your_email@example.com"
# 產生一組新的ssh金鑰,並以提供的email做標記
使用default settings所以按Enter繼續


Step 3. 輸入一組passphrase
看個人需求要不要設定,官網是建議設定一組好的passphrase嚕!


Step 4. 產生成功並將金鑰交給ssh-agent保管
出現此訊息代表成功!

接著,將金鑰交給ssh-agent保管,
ssh-add ~/.ssh/id_rsa

Step 5. 複製public key交給Github
打開~/.ssh/id_rsa.pub,不要新增或空格或空行,全選複製,
登入Github,進入account seetings,

左列選SSH keys,
點Add SSH key,進入後新增key title名稱,並在key欄位貼上剛複製過來的public key,
最後點選Add key完成交public key給Github

Step 6.驗證金鑰設定
ssh -T git@github.com
# 遠端至Github
別擔心這訊息,正常現象,type "yes"繼續,

到此代表金鑰成功設定了!

Ref.

2014年3月30日 星期日

[git]Git的使用

設定用戶名,依此類推
git config --global user.name [XXX XXX]
查看git setting
git config --list
查看help
git help
加入追蹤
git add [filename]
刪除檔案(-f 強制刪除)
git rm -f [filename]
保留檔案,僅從staging area移除
git rm --cached [filename]
要開始用Git要先建立一個Repository(簡稱repo),
有2種方法可以取得repo,一種是將現有的專案導入Git,另一種是從其它伺服器複製(clone)一份已存在的Git儲存庫,
第1種方法,只要切換到專案目錄並執行:
git init
這個命令就會建立名為 .git 的子目錄,這個目錄會包含一個Git儲存庫架構必要的所有檔案,
第2種方法,配合想取得現有的Git repo的網址然後使用 git clone,
(下載某Git repo, NAME可加可不加,是個人是否要更改名稱)
git clone [url] [new folder NAME]
在某個Repository檢查目前 Git 的狀態
-->On branch master: 表示正在名為 master 的 branch 上
git status
查看追蹤中有修改的code
經過git add 變成了 Changes to commit,這個狀態叫做 "stage" ,修改過但還沒使用 git add 的檔案稱為 unstage
git add . 可以一次把修改過或新增加的檔案都丟進stage狀態-->但很容易不小心加入一些不必要的檔案,所以不建議這麼做,手動將要加入的檔案git add丟入stage才是最好的方法!
git diff
把某檔案從staging area改回到unstaging(檔案內容不變)
git reset HEAD [filename]
git commit
#commit時盡量清楚的表達該次commit的內容,以後看才不會霧煞煞,同事或接手的人才不會有如閱讀天書
使用 -m 可不開editor, 快速提交
git -m "message"
git commit -a -m 'commit -message'
修改上一次的 commit 訊息
git commit --amend
查看過去 commit 的紀錄 git log
output所有log
git log
output所有log(較簡潔)
git log --pretty=oneline
git log --pretty=format:"%h : %an : %ar : %s"
最後這 2週的 log
git log --since="2 weeks ago"
output 最後2筆
git log -p -2
整理一下,平常coding和用git的過程
出現修改動機-->修改檔案-->丟進stage( git add )-->提交( git commit )-->繼續...
有些檔案不希望加入版本控制的追蹤,可以將他們加入 .gitignore 中讓 Git 忽略他們
vim .gitignore: 打開 .gitignore
增修設定.gitignore檔(可參考https://github.com/github/gitignore)
Ref.

2014年3月20日 星期四

[C/C++]二維陣列的傳遞

我們都知道,
C語言是以陣列第一個元素的位址當成是陣列的位址(也就是說-->陣列名稱本身就是存放陣列位址的變數),
在c裡,陣列傳遞是採用傳址呼叫(call by address or call by pointer),
因為在呼叫函數傳遞參數時,無法將整個陣列傳遞(因為陣列可能很大),因此傳的是陣列開頭的位址,
okay,複習一下參數傳遞的觀念,
分為傳值(call by value)、傳址(call by address)、傳參考(call by reference)3種,
1.傳值call by value
當函數被呼叫時,將主程式的變數"複製"一份給副函數,主程式的變數跟副程式複製來的變數互相獨立,並且有各自獨立的記憶體空間,
假設main()呼叫函式funcB(p, q),則funcB中的p和q是把main()傳入的參數「複製」一份,
funcB()對p, q所做的任何運算都不會影響到main()中的p和q,因為funcB()執行完後,不會把複製的p, q丟回給main()。
寫成code:
void swap( int i, int j );
int main()
{
 int i=5, j=10;
 printf("before swap:i=%d(add=%p) j=%d(add=%p)\n",i,&i,j,&j);
 printf("swap()work\n");
 swap(i,j);
 printf("i j in main():i=%d(add=%p) j=%d(add=%p)\n",i,&i,j,&j);
 return 0;
}

void swap( int i, int j )
{
 int temp;
 temp = i;
 i = j;
 j = temp;
 printf("i j in swap():i=%d(add=%p) j=%d(add=%p)\n",i,&i,j,&j);
}
可以看到output中,main()和swap()裡的i和j是獨立的(記憶體位址也不同),
而經過swap進行變數互換後,也沒影響到main()裡原本的變數值,

當換成傳遞陣列時,可以看到結果不一樣了,
void timesTwo( int arr[] );
int main()
{
 int arr[3]={1,3,5};
 for(int i=0; i<3; i++)
 printf("before swap:arr[%d]=%d(add=%p)\n",i,arr[i],&arr[i]);
 printf("arr[] add=%p\n",arr);
 printf("swap()work\n");
 timesTwo(arr);
 for(int i=0; i<3; i++)
 {
  arr[i] = arr[i]*2;
  printf("arr[] in main():arr[%d]=%d(add=%p)\n",i,arr[i],&arr[i]);
 }
 printf("arr[] add =%p\n",arr);
 return 0;
}

void timesTwo( int arr[] )
{
 for(int i=0; i<3; i++)
 {
  arr[i] = arr[i]*2;
  printf("arr[] in swap():arr[%d]=%d(add=%p)\n",i,arr[i],&arr[i]);
 }
 printf("arr[] add =%p\n",arr);
}
證實了開頭所說,C是以陣列第一個元素的位址當陣列的位址,且採用傳址(call by address)方式,
呼叫副函式timesTwo()後,函數所做的改變,直接改變main()裡array的值,這就是傳址(call by address),

傳址同樣可以用在一般變數,只要加上pointer即可,這方法可以讓函數直接改變原本變數值,也省去複製的步驟和記憶體空間,
void swap( int *i, int *j );
int main()
{
 int i = 5, j = 10;
 int *pt1 = &i;
 int *pt2 = &j;
 printf("before swap:\ni=%d(add=%p)\tj=%d(add=%p)\npt1=%d(add=%p)\tpt2=%d(add=%p)\n\n",i,&i,j,&j,*pt1,pt1,*pt2,pt2);
 printf("swap()work\n");
 swap(pt1, pt2);
 printf("i j pt in main():\ni=%d(add=%p)\tj=%d(add=%p)\npt1=%d(add=%p)\tpt2=%d(add=%p)\n\n",i,&i,j,&j,*pt1,pt1,*pt2,pt2);
 return 0;
}

void swap( int *i, int *j )
{
 int temp;
 temp = *i;
 *i = *j;
 *j = temp;
 printf("i j pt in swap():\ni=%d(add=%p)\tj=%d(add=%p)\n\n",*i,i,*j,j);
}
swap()呼叫前後,main()的i j跟swap裡i j用的都是同一塊記憶體,經過swap後,也因此i j直接互換的結果直接改變在main()裡,
這也是為什麼call by address又叫call by pointer,然後本質上他也是call by value的關係了!

當寫到2維陣列(或多維陣列)時,赫然發現事情已經不是如上所想的簡單了,
首先,這樣的陣列傳遞已經無法通過compile了,因為Compiler不知如何翻譯...待會會解釋why,
void timesTwo( int arr[][] );
int main()
{
 int arr2[2][4]={ 1,3,5,7,2,4,6,8 };
 ...
}
如果這樣寫就可以通過compile,但把維度寫死一點都不彈性,未來要傳不同維度array給函數,不就哭了,
void timesTwo( int arr[2][4] ) {};
所以要換成這樣的寫法較佳,
void timesTwo( int arr[][4] ) {};
或這樣,
void timesThree( int (*arr)[4] ) {};
結果都是一樣,並且成功傳給function顯示,

2維陣列的行和列,其實是我們為了清楚理解陣列元素排列而想像出來的,實際上在記憶體配置並非如此,而是以線性模式配置,
不管幾維陣列,都是分配成一塊連續的記憶體空間去處理陣列,
如int arr2[2][4]陣列會分配成2*4*sizeof(int)大小記憶體區塊(如圖),依此類推,

如果要走訪2維陣列的話,要把它對應成一維來處理,
假設陣列int arr2[2][4]={ {1,3,5,7},{2,4,6,8} },
我們要存取arr2[p][q]的值,從記憶體觀點,我們要從arr2[p]的開頭後走q個單位到達arr2[p][q].
所以可以如此表示:arr2[p][q]=p*4+q

code可以這樣寫
void arrFour(int *arr, int rol, int col)
{
 for(int i=0 ; i<rol ; i++) {
  for(int j=0 ; j<col ; j++) {
   arr[i*col+j] = arr[i*col+j]*2;
   printf("array[%d][%d] in arrFour()= %d, address=%p\n", i, j, arr[i*col+j], &arr[i*col+j]);
  }
 }
 printf( "address of array arr2 in arrFour()=%p\n", arr );
}

成功更改array每一個元素,可以看到arrFour執行前後,main()和function裡所使用的記憶體位置都是同一塊,改變也直接作用在原本array的value上,
這樣的寫法也增加了使用上的彈性,不用在宣告函數時寫死,
這也解答了為何 void timesTwo( int arr[][] ) 這樣寫無法compile了,因為compile無從計算起位置.

2014年3月14日 星期五

[SAS] macro的使用

Macro又名巨集,是非常實用的SAS coding技巧,
當你需要執行某程序,並且反覆執行它時,
最簡單的就是copy-paste..copy-paste..copy-paste..copy-paste這段程序,
ex.
假設手中有2005-2010 4筆資料(a2005 - a2008),想知道各年中y_05跟x的OR值等統計資訊,
*直覺懶人法;
proc logistic data=a2005;
  model y1(event="1") = x1;
run;
proc logistic data=a2005;
  model y2(event="1") = x2;
run;
proc logistic data=a2006;
  model y1(event="1") = x1;
run;
proc logistic data=a2006;
  model y2(event="1") = x2;
run;
...
...
...
proc logistic data=a2008;
  model y2(event="1") = x2;
run;
但是,我們都知道這是很笨也很沒效率的作法,也不符合優雅coding的理念,
所以macro是有學起來的必要性的,
如果引進macro寫法會變成怎樣呢,
OPTION NOSYMBOLGEN MPRINT;
%MACRO logiMc(year, y_vb, x_vb);
  proc logistic data=a&year;
    model &y_vb(event="1") = &x_vb;
  run;
%MEND logiMc;

%logiMc(2005,y1,x1)
  %logiMc(2005,y2,x2)
    %logiMc(2006,y1,x1)
      %logiMc(2006,y2,x2)
        %logiMc(2007,x1,y1)
          %logiMc(2007,x2,y2)
            %logiMc(2008,x1,y1)
              %logiMc(2008,x2,y2)
MACRO實際改寫出來的logistic程式碼只有4行(%MACRO和%MEND中間包的code),
原始寫法大約24行左右,節省了20行!
要不要學呢?! 當然看個人: )
其實macro不難,只是多了%和&符號而已,和一些參數設定的概念,
解釋如下:
由&開頭的變項稱為"巨集變項",
在要重複執行程序以外的指令程序,開頭要加上%,姑且稱作"巨集程序",
OPTIONS NOSYMBOLGEN MPRINT;      *在log檢視巨集和變數內容;
%MACRO logiMc(year, y_vb, x_vb);  *%MACRO-->宣告巨集的開頭,以及巨集名稱為logiMc,巨集接收3個參數year, y_vb, x_vb;
  proc logistic data=a&year;  *此處往下3行就是要重複執行的程序所在;
    model &y_vb(event="1") = &x_vb;  *由&開頭的巨集變項,會不斷被下方設定的巨集變數組代換,達到重複執行的目的;
  run;
%MEND logiMc;                    *%MEND-->宣告巨集的結尾;

/***巨集會來此處抓取設定好的巨集變數組,在程式區不斷做代換;**/
%logiMc(2005,y1,x1)			
  %logiMc(2005,y2,x2)
    %logiMc(2006,y1,x1)
      %logiMc(2006,y2,x2)
        %logiMc(2007,x1,y1)
          %logiMc(2007,x2,y2)
            %logiMc(2008,x1,y1)
              %logiMc(2008,x2,y2)
了解macro的精神後,就可以自由配合do, while, if-then, cat, 或甚至把多樣程序包到一個macro裡面,
for example:
先利用暫存檔作條件判斷
-->做retain 資料處理
-->再依條件output我要的檔案
//此處無需了解變數是什麼,只需了解怎麼編寫這樣的macro
OPTIONS NOSYMBOLGEN MPRINT; 
%MACRO test(o_y, o_y1, m_flag);
  %IF &m_flag=1 %THEN %DO;
    DATA WORK.in7; set WORK.in6;
        if season=&o_y & mdy(12,1,&o_y) <= indate < mdy(2,28,&o_y1) then output;
      run;

    DATA WORK.in8; set WORK.in7;
      by id;
        retain flu&o_y 0;
        flu&o_y = flu&o_y+1;
        if first.id then flu&o_y = 1;
    run;

    DATA in&o_y; set WORK.in8;
      by id;
        if last.id then output;
        keep id flu&o_y;
    run;
%END;
%MEND subset;
  %subset(2004,2005,1)
    %subset(2005,2006,1)
      %subset(2006,2007,1)
這邊會發現我多加了一條"%IF &m_flag=1 %THEN %DO;"和一個新參數"m_flag",
其實他的用意很簡單,就是"開關"的功用,
利用"如果m_flag=1(打開)就執行此組巨集變數"的概念,可以快速開關某組變數要不要跑巨集,
//進階寫法
當變數太多時,可能碰到設定巨集變數組麻煩的情況,
這時候可以配合do來達到更簡潔的寫法,
ex.
*記得,巨集語法開頭要加%;
%MACRO box( xStart, xEnd );
  %do xValue = &xStart %to &xEnd;
    proc surveylogistic data=aa;
      model y = &xValue * &xValue;
    run;
  %end;
%MEND box;
%box( 1, 16 )
Like this ! 歡迎提供補充和建議! : )

2014年2月19日 星期三

[Linux] screen的使用

最近因為專案需要跑大型數據模擬,常需要跑來中研院這邊登錄他們的server做simulation,
有時候模擬跑起來要很久很久,
如果程式沒結束就退出遠端,正在run的程式可能就會當掉,
因此藉機學到了Linux中強大的screen功能!
screen是linux上一個很好用的功能,可以在一個terminal下開啟多個視窗執行,又可以彼此切換,藉由每一個process的PID去modified,
簡單來說,又可以多分頁工作,又可以離線後繼續工作,如此好物,怎能不學!

screen的簡易指令:
screen      #第一次執行會創立一個running SHELL的單一視窗
            #(open a screen session for processing)
ctrl+a+c    #開啟下一個新的單一視窗並切換過去(change to new worker)
ctrl+a+d    #脫離(detach)目前的 screen ,並放到背景執行(jump out of screen),
            #離線繼續工作的強大指令,要在連上只需使用screen -r PID即可
screen -r PID    #選擇一個screen session 進入該程序
screen -ls       #查看所有screen sessions(show the screen working status)
kill PID         #kill process
說明:
平常工作寫或跑到一半就可以把它detach掉,丟到後臺執行後會回到還沒進screen的狀態,此時process其實都還在執行,就算logout也不會停止。
要在連上執行中的process,只要在login後,用screen -ls查看process的PID,在用screen -r PID即可回復該程序!
程序結束後,也只要用kill PID就可以跟該程序說bye bye嚕!

補充:
screen -R      #重新連接最近卸離的 screen 工作環境
screen -d PID  #強制 detach,以便「接手」過來
screen -wipe   #將廢棄的 screen 工作環境清除
exit           #關閉視窗(若只剩一個視窗則為關閉screen, close the screen)
top            #linux中的動態程序觀察功能,查看遠端主機終有哪些程序在執行
               #(leave top->press "q")
補充2:
ctrl+a+n       #Next == 切換到下個 window
ctrl+a+p       #Previous == 前一個 window
ctrl+a ctrl+a  #Other == 在兩個 window 間切換
ctrl+a+w       #Windows == 列出已開啟的 windows 有那些
ctrl+a+0       #切換到第 0 個 window
ctrl+a+1..9    #切換到第 1..9 個window
ctrl+a+a       #發出 C-a,在 emacs, ve, bash, tcsh 下可移到行首
ctrl+a+t       #Time,顯示當前時間,和系統的 load
ctrl+a+K(大寫)  #kill window,強行關閉當前的 window
ctrl+a+[       #進入 copy mode,在 copy mode 下可以回滾、搜索、複製就像用使用 vi 一樣
ctrl+b+Backward  #PageUp
ctrl+f+Forward   #PageDown