2015年9月9日 星期三

速記:Linux下的常駐服務管理(Sys-V vs. Systemd)


Debian決定之後, 看來未來init system的選項已經沒什麼爭議, 除了準備了解systemd之外, 也備忘早年各distro用來管理sys-v服務的工具。

Systemd:

---
systemd以一支systemctl進行服務的設定,
原本/etc/init.d/裡的daemon現在的位置在/lib/systemd/下,具體位置各家可能有所調整,但是管理工具的用法都相同。

啟動:systemctl start foobar.service
停止:systemctl stop foobar.service
重新啟動:systemctl restart foobar.service
重讀設定:systemctl reload foobar.service
顯示狀態:systemctl status foobar.service
列出全部:systemctl list-unit-files --type=service 或 ls /etc/systemd/system/*.wants/
列出全部開機自行啟動的服務:systemctl list-unit-files|grep enabled
設定開機啟動:systemctl enable foobar.service
設定開機不啟動:systemctl disable foobar.service
查詢是否被設為開機啟動:systemctl is-enabled foobar.service

原本的runlevel機制由target取代:

telinit 3 --> systemctl isolate multi-user.target 或 systemctl isolate runlevel3.target
init 5 --> systemctl isolate graphical.target 或 systemctl isolate runlevel5.target

設定開機自動進入的runlevel:

在systemd中不使用/etc/inittab, default runlevel是由soft link實現,

例如default runlevel 3:
ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target

但是由於default.target的位置每家不太一樣, 比較合適的作法是:
systemctl set-default -f multi-user.target


Sys-V:

列出全部: ls /etc/init.d/
啟動: /etc/init.d/{SERVICENAME} start
停止: /etc/init.d/{SERVICENAME} stop
設為開機自動啟動: cd /etc/rc3.d; ln -s ../init.d/{SERVICENAME} S95{SERVICENAME}
移除開機自動啟動: rm /etc/rc3.d/*{SERVICENAME}
切換runlevel: telinit 3
設定default runlevel: sed s/^id:.*:initdefault:/id:3:initdefault:/

除此之外各大Distro於Sys-V時期也有各自的管理工具:

Redhat(service/chkconfig):

啟動:service {SERVICENAME} start
停止:service {SERVICENAME} stop
重新啟動:service {SERVICENAME} restart
重讀設定:service {SERVICENAME} reload
顯示狀態:service {SERVICENAME} status
列出全部:chkconfig --list
設定開機啟動:chkconfig {SERVICENAME} on
設定開機不啟動:chkconfig {SERVICENAME} off
查詢是否被設為開機啟動:chkconfig {SERVICENAME}

Debian(update-rc.d/invoke-rc.d):

啟動:invoke-rc.d {SERVICENAME} start
停止:invoke-rc.d {SERVICENAME} stop
重新啟動:service {SERVICENAME} restart
重讀設定:service {SERVICENAME} reload
顯示狀態:service {SERVICENAME} status
列出全部:rcconf
設為開機自動啟動: update-rc.d {SERVICENAME} default
移除開機自動啟動: update-rc.d -f {SERVICENAME} remove
設定啟動與關閉的runlevel:
update-rc.d {SERVICENAME} start [order] [runlevel]
update-rc.d {SERVICENAME} stop [order][runlevel]
例如 update-rc.d {SERVICENAME} start 20 0 1 2 6
表示SERVICENAME在runlevel 0, 1, 2, 6以編號20的次序啟動

Ubuntu(upstart): 

列出全部:initctl list
啟動:initctl start {SERVICENAME}
停止:initctl stop {SERVICENAME}
設為開機自動啟動:
 1. /etc/default/{SERVICENAME}, 將ENABLED=...改為ENABLED=1
 2. /etc/init/{SERVICENAME}.override, 要嘛沒這檔案, 不然裏面必須包含start字樣, 不是manual
移除開機自動啟動: echo manual > /etc/init/{SERVICENAME}.override

參考:

http://fedoraproject.org/wiki/SysVinit_to_Systemd_Cheatsheet

2015年8月4日 星期二

gedit外掛iconv - 轉換文檔編碼

前幾年還得煩惱桌機該不該utf化的問題,隔了幾年各distro改了就順勢改了,
反正早年的big5檔案多半現在都是archive,不是偶爾翻出來mud mud回味一下好像不轉影響也不大。

可是事情常常不像憨人想的那樣,處理電影字幕檔就是其中一種,觀眾都就位了結果片子vlc出來是亂碼是個超級敗興的狀況。
所以以下指令通常很熟練:
big -> utf-8
$ iconv -f big5  -t utf8  test.big5.txt  > test.utf8.txt       

gb2312 -> utf-8
$ iconv -f gb2312 -t utf8 test.gb2312.txt > test.utf8.txt

有些字幕來的時候就是簡體utf-8,年輕人將就著啃沒問題,可是長輩不喜歡,所以還得會這招:
iconv -f utf8 -t gb2312 test.gb.utf8.txt | iconv -f gb2312 -t big5 | iconv -f big5 -t utf8 > test.big5.utf8.txt

看到沒? 老派作風的乾淨利落真是令人激賞。

但是有的時候想看電影就是不想動腦袋,這時候會想翻翻看是不是原生desktop app就能有這功能...
好,沒有;那就自己弄
gedit->工具->manage external tools->+

新增一個gedit的外掛,名字例如叫作iconv big5 utf8,右方shell script的部份填入
     iconv -f big5 -t utf8 $GEDIT_CURRENT_DOCUMENT_NAME
輸入:目前文件
輸出:取代目前的文件

以後gedit打開字幕檔時就可以工具->External tools->iconv big5 utf8,簡體轉萬國或是簡繁互轉依此類推。


#當然是抄來的,credit to http://blog.yam.com/ddy1280/article/856796
#批次轉換的話要多費點手腳,幸好google很好用,Tsung有寫怎麼做:
  http://blog.longwin.com.tw/2008/07/convmv_utf8_big5_convert_linux_2008/

Vim plugin - YouCompleteMe

Ubuntu 15.04下安裝完youcompleteme之後通常會遇到兩個如同月經般的老問題:
1. YCM要求手動編譯(使用cmake)
"ycm_client_support.[so|pyd|dll] and ycm_core.[so|pyd|dll] not detected; you need to compile YCM before using it. Read the docs!"
$ (Optional) sudo apt-get install cmake
$ cd ~/.vim/bundle/YouCompleteMe
$ ./install.sh --clang-completer

2. cmake找不到python lib
"  STDERR:
Your C++ compiler supports C++11, compiling in that mode.
CMake Error at /usr/share/cmake-3.0/Modules/FindPackageHandleStandardArgs.cmake:136 (message):
  Could NOT find PythonLibs (missing: PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS)
  (Required is at least version "2.6")
Call Stack (most recent call first):
  /usr/share/cmake-3.0/Modules/FindPackageHandleStandardArgs.cmake:343 (_FPHSA_FAILURE_MESSAGE)
  /usr/share/cmake-3.0/Modules/FindPythonLibs.cmake:197 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
  BoostParts/CMakeLists.txt:30 (find_package)"
安裝python-dev即可解決
$ sudo apt-get install python-dev

3. clang不提供32位元的版本
"  STDERR:
Your C++ compiler supports C++11, compiling in that mode.
CMake Error at ycm/CMakeLists.txt:64 (message):
  No pre-built Clang 3.6 binaries for 32 bit linux.  You'll have to compile
  Clang 3.6 from source.  See the YCM docs for details on how to use a
  user-compiled libclang.
 
如果系統上確定已經安裝好libclang,試看看以下參數:
$./install.sh --clang-completer --system-libclang

或是參考這些地方自己編
1.https://solarianprogrammer.com/2013/01/17/building-clang-libcpp-ubuntu-linux/
2.http://www.cnblogs.com/csuftzzk/p/3435710.html
3.http://www.linuxzen.com/vim-dai-ma-bu-quan-he-jian-cha-youcompleteme-syntastic.html

2015年7月12日 星期日

VIM中的縮排(Tab)

程式設計師間對於縮排鍵(Tab)的使用真是百家爭鳴,
主要的問題是:
1. 一次縮排八個字元太多,縮排沒幾次code都看不見了。
2.在各家環境中,一個Tab鍵造成的縮排可能不同於你想像中的8個字元(Characters)長,而且tab鍵看不見,某些文字處理情境容易造成錯誤(例如弄混tab跟space之類)。

目前看到的多半都是讓一次的縮排使用4個字元,但是具體作法就百家爭鳴了,Vim提供以下幾種方式:
1. set tabstop=4
     改變Tab鍵為一次縮進4個字元,最好是別這樣改,因為其他程式不知道Vim改掉Tab的縮進值,格式怕跑掉,而且某些印表機吃到一個Tab鍵就是印八格,改到這種的印出來格式跑掉就糗了。
2. set softtabstop=4
     混用Tab與space,保留tabstop=8,改成每次按下Tab就插入4個Space,再度按下Tab時會先刪除原來的4個Space,改成插入1個Tab符號(^I)。
3. set smarttab
     混用Tab與space,用於縮排時每個縮排符號使用shiftwidth,而在第一個非空白字元後的Tab就真的使用(^I)
4. set expandtab
     不使用縮排符號(^I),改以Space替代,如果縮排寬度沒改的話就是8個Space,<BS>要按8次刪除

支持使用space的人認為就是直接把(^I)從文檔中全部拿掉,^I可能依系統不同造成佔用不同長度的空間,改成Space就是每個Space固定一個字元。

反方說法是保留其他文檔使用者自訂Tab寬度的權力,畢竟有的人愛縮排2,縮排3不一定,而且一個(^I)比八個Space佔用較少的空間。

我目前使用的是這樣,必要之惡:
set tabstop=8
set softtabstop=4
set expandtab

不管使用縮排符號與否,對於已經存在的文檔最好是統一一下,此時可以使用:%retab!
將文檔內縮排符號改為Space:
:set expandtab
:%retab!
將文檔內縮排符號改為^I:
:set noexpandtab
:%retab!

#其實set list可以讓Vim將Tab符號顯示為^I, 將行末顯示為$,只是Tab或是行數多的時候很醜,set nolist可以關掉。

VIM: Buffers vs Tabs

Vim在7.0開始的分頁(Tabs)功能對於依靠直覺使用工具的人來說應該不難理解,就像Firefox、Chrome、Ultraedit之類上的應用一般,開一個新檔案就開一個新頁籤(tab)去放,
 一個tab一個檔案,很清楚。

但是對於老用戶如我來說,新出現的分頁功能要我照Windows下的慣用用法來用實在是有夠彆扭,因為Vim本來就有運作良好的buffer機制可以進行多檔編輯,
交互參考還可以搭配vs(plit)開兩個視窗來做,chrome上的分頁用法套在這裡貌似不太適用。

事實上Vim的頁籤功能原本的設計意圖的確不是這樣用,開始說明之前先回顧一下Vim的buffer與window:

Vim所謂的buffer,指的就是編輯中的文檔(Text),有一個比較傳神的形容叫做instance of file,
當Vim打開一個檔案要編輯的時候,他事實上是將整個檔案讀到記憶體中的一塊空間,
我們編輯的是記憶體裡的副本,因此改完了要:w寫回去,
而當Vim同時編輯兩個檔案的時候,所作的就是將第二個檔案讀到另一塊記憶體的空間中,我們隨後可以使用bnext/bprev在兩管buffer中切換。

而 Vim中的window指的是一種顯示buffer內容的方法,是"任何"buffer,一次一個,
當我們正在編輯一個檔案,我們可以split開啟另一 個window,此時另一個window顯示的還是原本在編輯的buffer,
隨後我們bnext切換到另一個buffer,前面提到的交互參考就做出來 了。

以上是buffer與window,根據Vim的文件,buffer、window與tab的定義是這樣:
buffer: the in-memory text of a file.
window: viewpoint of a buffer.
tab: a collection of windows.

來 做個實驗,我們打開兩個檔案,使用垂直分割讓他們能同時顯示,然後:tabnew開一個新的tab,這次水平分割兩個window讓他們讀進方才的兩個檔 案,:tabnext來回切換tab, 
你會發現tab就真的只是讓window以不同形式layout,他們事實上還是共用同一組buffers。

具 體上tab的用法其實也就是這樣,讓你可以切換不同的layout,可以一個tab開啟.c與.h做交互參照,然後另外一個tab單開.c檔專心做編輯,
也可以一個tab編輯一個專案,另一個tab分開另一個專案,當然要一個tab開一個不同的檔案還是可以的,只是我會說那不是原本設計的意圖 (intention)。

2015年7月11日 星期六

VIM的剪貼簿(register)

關於在Vim裡的複製與貼上,help copy-move 可以得到詳細的說明。
較為特別之處是Vim提供了暫存器(register)的觀念,可以將他想成buffer的概念,
剪下來的東西分別以自動或手動的方式放置到不同的register,稍後就可以統一處理。

想像一個場景,用Windows的筆記本編輯一個檔案,你發現想要複製的內容分佈在檔案的不同部位,甚至是不同的檔案中,
通常的操作就是捲到目標處,複製,回來貼上,捲到下個目標處,回來再貼上,打開另一個檔案,重複本行的行為。

使用Vim的情景會是找到目標,複製到某暫存器,繼續找下一個目標,複製到另一個暫存器,打開別的檔案找到目標,複製到另一個暫存器,一直到暫存器用完或是全部複製作業結束,然後回來原先的編輯處按需要一個一個貼出來,以下是常用的register及功能介紹。

Vim總共有九種類型的暫存器, 共74個,
使用時按"接著要使用的暫存器,需要配合d、c、s、x、p等指令,
例如"a2x表示剪下游標後的兩個字元存入"a暫存器, "ap表示將a暫存器內容貼在游標處,
1. unmamed register ""
2. number register "0 ~ "9
3. small delete register "-
4. 26 named register "a ~ "z 或 "A ~ "Z
5. 4 read-only register ":  ".  "%  "#
6. expression register "=
7. selection and drop register "* "+ "~
8. black hold register "_
9. last search pattern register "/

1. unnamed register:
     Vim執行d, c, s, x, 等刪除行為, 或是複製行為y時就會將被剪下來或是複製下來的內容放進這個暫存器, 不管有沒有指定要使用那一個暫存器, 也可以說這個暫存器就是指向最後一個使用的暫存器, 在Vim內使用複製、剪下與貼上時,如果沒有指定使用哪個暫存器,東西就是存在unnamed register,順帶一題指定存入""的話,實際會寫入"0。

2. number register:
     number register也是屬於自動使用,沒指定暫存器的話,最近一次的複製(yank)內容會存到"0, 而最後一次的刪除(x|d)或變更(c)會將被去掉的內容放在"1 ,每次"1被換成新的內容時,前一次存著的內容就會推到"2,以此類推,最後的"9放的內容會自動丟掉。

3. small register:
     類似"1, 差別在少於一行的內容會放在"-, 大於一行的內容放在"1

4. named register:
     給你手動使用的register, 指定存到小寫暫存器("a ~ "z)時以新的內容置換掉原來暫存器的存放內容,指定存到大寫暫存器("A ~ "Z)時新的內容會被附加在原來內容的後面。

5. 4 read-only register:
     這四個暫存器值是Vim自己填的,你只能用p或P貼出去。
     ".     -     最後以i或o命令插入的文字, 打了1234abcd, ".裡面放的就是1234abcd
     "%     -     當前編輯的檔名
     "#     -     替代用檔名(alternate name)
     ":     -     最後執行的命令, 例如執行shell命令:! ls, ":裡放的就是! ls

6. expression register:
     read only register, 這個暫存器的用法有點不容易搞清楚,說明文字裡說的是讓我們評估Vim的表示式(expression),如果表示式的結果能被轉換成字串,字串就可以被插入當前游標所在地,很拗口的說法。
     實際上的使用可以當作一個簡易的計算機,在輸入模式時按下Ctrl+r及=,游標會顯示在命令行讓你鍵入命令,我們輸入一個算式例如4*2,按下enter後,結果8就會被插入文件中游標最後位置。
     所謂的表示式並不限於數學的運算式,只要是按下:後能在命令列輸入的命令就可以用,暫存器會存下執行的最後結果供你隨後使用。

7. selection and drop register:
     用在圖形界面中與其他應用程式共用剪貼板,一般來說會被WM或是Windows的內建功能接管剪貼簿,這個功能實驗不出來。

8. black hols register:
     像是/dev/null,寫進去之後就不見了,也貼不出東西,當不想打亂register的時候用

9. Last search register:
     這個register存放最後執行的search pattern,主要影響到n及hlsearch,意思是說當你想更換n及hlsearch的對象,但是又不想真的執行search時,使用:let設定這個register的值, ex: let@/='search_target'

#順道一提,:reg {arg}與:dis {arg}列出指定的register及值,:reg沒指定對象的話就列出全部register。

2015年5月19日 星期二

製作Windows 7自動安裝光碟

  • 準備項目:
  • 將win7原版光碟內容複製到硬碟的某個目錄(以c:\win7為例), 確定sources\install.wim是可讀寫屬性
  • 安裝WAIK(X86:wAIKX86.msi, X64:wAIKAMD64.msi)
  • Windows系統映像管理員->檔案->新建回應檔案, WAIK要求開啟windows映像時指向c:\win7\sources\install.wim
    • 左下角Windows映像視窗中挑選components右鍵加入至中間回應檔案視窗, 大部分設定都在1.Windows PE與7.oobeSystem中
      • 1.WindowsvPE 
        • Microsoft-Windows-International-Core-WinPE
          • InputLocale=zh-TW
          • Layered Driver=1
          • SystemLocale=zh-TW
          • UILanguage=zh-TW
          • UILanguageFallback=zh-TW
          • UserLocale=zh-TW
        • Microsoft-Windows-International-Core-WinPE\SetupUILanguage
          • UILanguage=zh-TW
          • WillShowUI=OnError
        • Microsoft-Windows-Setup
          • WillShowUI=OnError
          • EnableFirewall=true
          • EnableNetwork=true
          • Restart=Restart
          • UseConfigurationSet=true
        • Microsoft-Windows-Setup\DiskConfiguration
          • WillShowUI=OnError
        • Microsoft-Windows-Setup\DiskConfiguration\Disk
          • DiskID=0
          • WillWipeDisk=true
        • Microsoft-Windows-Setup\DiskConfiguration\Disk\CreatePartitions\CreatePartition
          • Extend=true
          • Order=1
          • Size=XXXX(Optional if Extend is true)
          • Type=Primary
        • Microsoft-Windows-Setup\DiskConfiguration\Disk\ModifyPartitions\ModifyPartition
          • Active=true
          • Format=NTFS
          • Label=System
          • Letter=C
          • Order=1
          • PartitionID=1
        • #備註: CreatePartition與ModifyPartition要互相搭配,可以看作一個是建立分割區,另一個負責格式化,以上範例會將整顆硬碟的空間分給第一個partition。
        • #備註: CreatePartition中的Extend表示使用剩餘磁碟空間,因此當需要分割為兩個以上分割區時,第一個CreatePartition的Extend設為false,要指定Size(MB),第二個CreatePartition中的Extend設為true,Size保持空白
        • #備註: ModifyPartition跟著CreatePartition跑,有幾個CreatePartition就有幾個ModifyPartition,重點在於開機分割區的Active要設為true,指定格式為NTFS,另外Order與Createpartition同步,PartitionID要指向對應的CreatePartition
        • Microsoft-Windows-Setup\ImageInstall\OSImage
          • InstallToAvailablePartition=false
          • WillShowUI=OnError
        • Microsoft-Windows-Setup\ImageInstall\OSImage\InstallTo
          • DiskID=0
          • PartitionID=1
        • Microsoft-Windows-Setup\UserData
          • AcceptEula=true
          • FullName=w7usr
          • Orgnize=N/A
        • Microsoft-Windows-Setup\UserData\ProductKey
          • Key=XXXXXX
          • #備註:試過在此輸入Key會導致自動安裝失敗,紀錄上顯示為不合法的金鑰
          • WillShowUI=OnError
      • 7.oobeSystem
        • Microsoft-Windows-International-Core
          • InputLocale=zh-TW
          • SystemLocale=zh-TW
          • UILanguage=zh-TW
          • UILanguageFallback=zh-TW
          • UserLocale=zh-TW
        • Microsoft-Windows-Shell-Setup
          • BluetoothTaskbarIconEnabled=false
          • DisableAutoDaylightTimeSet=true
          • DoNotCleanTaskbar=false
          • ShowWindowsLive=false
          • TimeZone=Taipei Standard Time
        • Microsoft-Windows-Shell-Setup\FirstLogonCommands\SynchronousCommand
          • CommandLinux=%SYSTEMDRIVE%\7-zip_X32\inst_7z920.cmd
          • #備註:放這的安裝檔造做成靜默安裝,用cmd檔包起來的話,裡面的路徑要寫成絕對路徑,cmd檔範例在文章最底部
          • Order=1
        • Microsoft-Windows-Shell-Setup\OOBE
          • HideEULAPage=true
          • NetworkLocation=Work
          • ProtecYourPC=3
        • Microsoft-Windows-Shell-Setup\UserAccounts\AdministratorPassword
          • Value=XXXXXXXXXXX
          • #備註:可直接輸入Administrator帳號的密碼
        • Microsoft-Windows-Shell-Setup\UserAccounts\LocalAccounts\LocalAccount
          • DisplayName=XXXXX
          • Group=Administrators
          • Name=w7usr
          • #備註:應答檔中新增一個或多個使用者帳號,可避免自動安裝停在新增使用者處
        • Microsoft-Windows-Shell-Setup\UserAccounts\LocalAccounts\LocalAccount\Password
          • Value=XXXXXXXXXX
  • 工具->驗證回應檔案, 若下方訊息視窗出現"沒有警告或錯誤"之後就可以儲存至c:\win7下,檔名固定為autounattend.xml
  • 將C:\Program Files\Windows AIK\Tools\PETools\x86\boot\etfsboot.com 複製到 C:\
  • 將C:\Program Files\Windows AIK\Tools\x86\oscdimg.exe 複製到C:\
  • 打開cmd到C:\
  • oscdimg.exe -bC:\etfsboot.com -h -m -nt -ois C:\win7 C:\win732.iso , 結束後win732.iso即可燒錄為自動安裝光碟
    • oscdimg.exe參數
      • -b: 將開機檔加到光碟映像中,參數與路徑間不須留空格
      • -h: 連帶隱藏目錄及檔案一併封裝
      • -m: 允許完成的ISO檔超過一片光碟片大小
      • -nt: 增強長檔名及NT 3.51的相容性
      • -o: 來源資料夾有相同檔案時僅加入一次,減少iso檔的大小
      • -oi: 忽略比對來源資料夾中已經壓縮過而不能再度壓縮的檔案,節省封裝時間
      • -os: 顯示合併過程
      • 以上三個參數可以合併為-ois

      inst_7z920.cmd範例
      (注意7-zip的x86與x64版的靜
      默安裝參數不同,X64板的參數/q INSTALLDIR="C:\Program Files\7-Zip")

      @echo off
      @echo Installing 7zip
      %SYSTEMDRIVE%\7-zip_X32\7z920.exe /S /D=C:\Program Files\7-zip
      SETLOCAL
      SET SC=HKLM\SOFTWARE\Classes
      SET Extn=001 7z arj bz2 cab chm cpio deb gz iso lzh nsis rar rpm tar z
      FOR %%j IN (%Extn%) DO >nul (
      REG ADD %SC%\.%%j /VE /D "7-Zip.%%j" /F
      REG ADD %SC%\7-Zip.%%j /VE /D "7z Archive" /F
      REG ADD %SC%\7-Zip.%%j\DefaultIcon /VE /D "\"%PROGRAMFILES%\7-Zip\Formats\%%j.dll\"" /F
      REG ADD %SC%\7-Zip.%%j\shell\open\command /VE /D "\"%PROGRAMFILES%\7-Zip\7zFM.exe\" \"%%1\"" /F
      )
      REG ADD >nul %SC%\7-Zip.001\DefaultIcon /VE /D "\"%PROGRAMFILES%\7-Zip\Formats\split.dll\"" /F
      ENDLOCAL
      @echo Done!