2010年8月17日 星期二

vim 的取代置換功能「s」

vim-logo.gif在 前面我們所談的那些可以說是比較基本的東西,但是對於一份文件來說,光有前面所介紹的游標移動、刪除等等功能是不足夠的。面對一份文件我們通常會因為某些 緣故而使得我們必須去修改當中固定出現的字串樣式(pattern)成我們想要的樣子。最常遇到的就像中文文件的標點符號問題,或是 un*ix 和 DOS 文件格式之間轉換常會有個 ^M 結尾會讓人覺得很討厭,又或是我們想要把一份 HTML 格式的文件去除掉它的 HTML tag。
對於這些事情來說,拿中文標點符號置換這個很多編輯器都做得到,簡單地說如果想更動的 pattern 是一個固定的字串,那對於一般編輯器來說都不會太困難,但是對於具有固定格式,但字串內容卻不一定的該怎麼辦?就像要去掉 HTML 格式中的所有 HTML tag?這就是 vim 開始大顯身手的地方了。

今天我們不談別的其他指令,就光談在 vim 中的「 :s 」指令。小寫 :s 表示置換(substitute)的意思,不過通常你用 vim 下 :h :s 指令的時候會看到這樣的畫面:
vim help for :s substitute
其實這一串東西就是在說 :s 這個指令的格式要怎麼下。
Range:
一般對於整份文件都要作置換的話,我都會下像這樣的指令:
:%s/, /,/g
最前面的「%」就是表示全域,也就是現在編輯的這一份文件都要作後面取代的工作。那這個指令就是說要把半形的逗點「,」變成全形「,」。那後面 「g」又代表什麼意思呢?在 g 這個欄位上的東西是用來表示對目前這個指令所做的額外的選項。就拿 g 來說, g 代表在文件中每一個出現的半形逗點都要置換成全形。或許你會問剛剛不是已經用「%」表示全域了嗎,怎麼又要用 g 呢?我應該這樣說,「%」用來表示從文件的第一行到最後一行。但是在比對(match)的時候,如果不加「g」這個額外選項的話, vim 只會把每一行比對到的第一個作取代,同行其他也 match 到的就不管了。所以用「g」表示每一行中每一個比對到的都要置換。
所以同理,如果你要把那些因為 un*ix 和 DOS 之間格式不合所造成的^M消掉的話,也只需要下成這樣就可以了:
:%s/^M//g
可是有時候你想要作置換的只是文件中的某一部份的話怎麼辦?不要緊,還記得選取模式嗎?在你想置換部分的開頭按下大寫「V」然後用移動游標(我們之前講的 vim 移動游標的方法在選取模式下都可以用)到你想要的位置之後按「:」就會跳到輸入指令的狀態,如下圖最下面那行看到的一樣:
vim selection for substitute
當然你很確定行數,你也可以這樣下:
:1,300s/vim/VIM/g
或者是如果你很確定要從現在游標所在行之後的所有行都置換,可以下成:
:.,$s/vim/VIM/g
冒號一開頭的那一小點「 . 」就代表游標現在所在行,「$」則用來表示最後一行。
或許聰明的你已經想到怎麼樣可以從現在所在行之前的都要置換了,
:.,1s/vim/VIM/g
不過當你這樣打的時候, vim 會跳出來一個訊息:
Backwards range given, OK to swap (y/n)?
這就是說你給了一個起始行數比結束行數還要大的範圍。這是因為 vim 所定的範圍都是從小到大,如果你要從大到小不是不行,只是多個訊息確認你沒有打錯罷了。
Pattern:
像前面說,固定字串像把半形逗點換成全形逗點這都還容易,如果只是格式固定,但是字串內容會變動怎麼辦?就像去 HTML tag 的時候就很麻煩。
還記得我們在淺談vim那時候提過的指令嗎?
  • :%s/\n/^V/g
  • :%s/《[^<》]*>//g
  • :%s/^V/\n/g
在中間的那一些 [^<>]*看起來像外星文字的,就是 pattern 比對的主力。事實上關於這些東西,我們在談 vim 的 search 搜尋功能的時候也有提到過一些。所以我們今天就來補一些上次沒有講到的東西。
假如我現在有一筆人名、電話的資料,由於是隨手記的,上面自然就是沒有排序過。那沒排序過對於想要在上面找資料的人就很麻煩。萬一人名記不太清楚, 電話號碼也記得七七八八,雖然說有 vim 方便的 search 功能,但總是感覺不足。(當然這只是假設情況,因為實際上可能大家都已經建立某種方便搜尋的資料庫了)
我們先假設人名、電話的對應長成這樣:
趙大明  1235478982
錢小名  1223450012
王孫李  5938123812
周渚衛  1384914191
沈以情  2345934981
那我可不可以讓它變成這樣子?
1235478982   趙大明
1223450012   錢小名
5938123812   王孫李
1384914191   周渚衛
2345934981   沈以情
我可以下這樣的指令完成這個工作:
:%s/\([^0-9]\{1,}\)\([0-9]\{1,}\)/\2 \1/g
前面橘色的部分 \([^0-9]\{1,}\) 用 \( \) 括起來的,表示這是一個的單元,之後就可以依照它出現的順序而使用 \1 \2,… ,來代表它。所以我們可以看到 [^0-9] 就表示非數字的部分,後面的\{1,} 如果你還記得的話,就是代表出現至少一次。不過這個時候DK長輩會跟你說用 vim 要文明一點,要用「\+」來代表至少出現一次。看個人喜好了,如果你願意多記一些代替的符號就多記一點,你可以用 :h /multi 看到更多這些替代符號。
所以把 pattern 用 \( \) 分開之後,我們就可以用 \1,\2 來把他們交換位置。
不過你可能會說這樣還沒排序啊。我們可以用選取模式把整份文件選起來,或是你懶得用上下左右改變,你可以用 ggVG (gg 跳到第一行之後,用大寫V進入選擇模式,以大寫G跳到最後一行)把整份文件選起來之後按 :!sort,這時候在你 vim 視窗的最底下就會變成這樣:
:’《,’》!sort
下去就會變成根據每一行的最前頭作排序的結果。所以結果就會變成:
1223450012   錢小名
1235478982   趙大明
1384914191   周渚衛
2345934981   沈以情
5938123812   王孫李
很簡單吧? :p
如果你願意配合暫存器( registers )的話,有時候也能省點力氣。在講 vim search 的時候,我們曾經提了用 搭配數字鍵 0 來把暫存器 0 的東西叫出來。同樣的,我們不管用 / 或是 ? 等等輸入字串的時候,事實上都已經把要搜尋的字串寫入「/」的暫存器裡面,所以當我們只是想置換的字串就是搜尋的字串的話,我們可以這樣做:
:%s//用來取代的字串/g
表示在按 之後按下「/」這個按鍵。這樣就可以把搜尋的字串叫出來並用之於置換指令上。
額外指令
我們剛剛在前面談到可以作像「g」這些的額外控制。那有哪些控制可以作呢?
比方說在我們作置換的時候,由於 vim 預設是有大小寫的差別,如果你不管大小寫都要取代的話,那可以用「i」這個額外參數來控制 vim 取代的時候就不管大小寫都會作取代的工作。
不過有時候,我們可能不太能確定是不是整份文件中的每一個都要取代,那我們就可以加「c」 confirm 確認參數來控制,那使用上也很容易。 vim 會在比對到之後問
(y/n/a/q/l/^E/^Y)?
  • y 是代表執行目前的取代。
  • n 是跳過。
  • a 代表 always ,就是從目前以後的取代都會執行。
  • q 則是不要作取代,並且離開詢問要不要取代的狀態,並回到指令模式或原來的模式下。
  • l 則是 last 的意思,就是目前這個取代執行後就離開詢問的取代模式,回到指令模式或原來的模式下。
  • ^E 表示往前一頁。
  • ^Y 表示往後一頁。
對於 :s 的用法到這裡我們就已經把常用的幾個方式都說完了。礙於篇幅,我也決定先寫到這裡就好,不然寫一大篇,可能連有興趣進來瞭解 vim 的人光看到就害怕了,怎麼還有辦法體會 vim 的好呢?其實關於 :s 的用法,還有 pattern 還有很多的方式在本篇中沒有提到,你可以在 vim 中用 :h :s 看到更多詳細的資料。今天就來 vim 吧!

from http://greenisland.csie.nctu.edu.tw/wp/2005/09/02/302/
-----------------------------------------------------------------------------------------------------------------------------------------

vi/vim 中可以使用 :s 命令來替換字串。該命令有很多種不同細節使用方法,可以實現複雜的功能,記錄幾種在此,方便以後查詢。

:s/vivian/sky/ 替換當前行第一個 vivian 為 sky

:s/vivian/sky/g 替換當前行所有 vivian 為 sky

:n,$s/vivian/sky/ 替換第 n 行開始到最後一行中每一行的第一個 vivian 為 sky

:n,$s/vivian/sky/g 替換第 n 行開始到最後一行中每一行所有 vivian 為 sky

n 為數字,若 n 為 .,表示從當前行開始到最後一行

:%s/vivian/sky/(等同於 :g/vivian/s//sky/) 替換每一行的第一個 vivian 為 sky

:%s/vivian/sky/g(等同於 :g/vivian/s//sky/g) 替換每一行中所有 vivian 為 sky

可以使用 # 作為分隔符號,此時中間出現的 / 不會作為分隔符號

:s#vivian/#sky/# 替換當前行第一個 vivian/ 為 sky/

:%s+/oradata/apras/+/user01/apras1+ (使用+ 來 替換 / ): /oradata/apras/替換成/user01/apras1/

1.:s/vivian/sky/ 替換當前行第一個 vivian 為 sky

:s/vivian/sky/g 替換當前行所有 vivian 為 sky

2. :n,$s/vivian/sky/ 替換第 n 行開始到最後一行中每一行的第一個 vivian 為 sky

:n,$s/vivian/sky/g 替換第 n 行開始到最後一行中每一行所有 vivian 為 sky

(n 為數字,若 n 為 .,表示從當前行開始到最後一行)

3. :%s/vivian/sky/(等同於 :g/vivian/s//sky/) 替換每一行的第一個 vivian 為 sky

:%s/vivian/sky/g(等同於 :g/vivian/s//sky/g) 替換每一行中所有 vivian 為 sky

4. 可以使用 # 作為分隔符號,此時中間出現的 / 不會作為分隔符號

:s#vivian/#sky/# 替換當前行第一個 vivian/ 為 sky/

5. 刪除文本中的^M

問題描述:對於換行,window下用回車換行(0A0D)來表示,linux下是回車(0A)來表示。這樣,將window上的檔拷到unix上用時,總會有個^M.請寫個用在unix下的過濾windows文件的分行符號(0D)的shell或c程式。

。 使用命令:cat filename1 | tr -d “^V^M” > newfile;

。 使用命令:sed -e “s/^V^M//” filename > outputfilename.需要注意的是在1、2兩種方法中,^V和^M指的是Ctrl+V和Ctrl+M.你必須要手工進行輸入,而不是粘貼。

。 在vi中處理:首先使用vi打開檔,然後按ESC鍵,接著輸入命令:%s/^V^M//.

。 :%s/^M$//g

如果上述方法無用,則正確的解決辦法是: [Page]

。 tr -d \"\\r\" < src >dest

。 tr -d \"\\015\" dest

。 strings A>B
6. 替換確認
我們有很多時候會需要某個字元(串)在文章中某些位置出現時被替換,而其它位置不被替換的有選擇的操作,這就需要使用者來進行確認,vi的查找替換同樣支持
例如
:s/vivian/sky/g 替換當前行所有 vivian 為 sky
在命令後面加上一個字母c就可以實現,即:s/vivian/sky/gc
顧名思意,c是confirm的縮寫

7. 其它

利用 :s 命令可以實現字串的替換。具體的用法包括:

:s/str1/str2/ 用字串 str2 替換行中首次出現的字串 str1

:s/str1/str2/g 用字串 str2 替換行中所有出現的字串 str1

:。,$ s/str1/str2/g 用字串 str2 替換正文當前行到末尾所有出現的字串 str1

:1,$ s/str1/str2/g 用字串 str2 替換正文中所有出現的字串 str1

:g/str1/s//str2/g 功能同上

從上述替換命令可以看到:g 放在命令末尾,表示對搜索字串的每次出現進行替換;不加 g,表示只對搜索

字串的首次出現進行替換;g 放在命令開頭,表示對正文中所有包含搜索字串的行進行替換操作

(原文地址: http://wzgyantai.blogbus.com/logs/28117977.html)

Windows和Linux文件共享新的途徑:Dokan

一、Dokan Library
  如果您想在Windows系統上創建一個新的文件系統的話,例如:改進FAT或NTFS文件系統,您就需要自己開發一個文件系統驅動。 在Windows系統上開發工作在內核模式的設備驅動程序是一件極為困難的事情。 使用Dokan庫(Dokan Library),您可以非常方便地創建自己的文件系統而不需要編寫設備驅動程序。 Dokan庫類似於Linux下的FUSE用戶空間文件系統,但是它工作在Windows下。
  Dokan庫包含一個用戶模式的DLL文件(dokan.dll)以及一個內核模式文件系統驅動(dokan.sys)。 Dokan文件系統驅動一旦安裝,您就可以在Windows上創建和普通文件系統一樣的文件系統。 使用Dokan庫創建的文件系統的應用程序稱為文件系統應用程序。 來自用戶程序的文件操作請求(例如:CreateFile,ReadFile,WriteFile等)將被發送的Windows輸入/輸出子系統(運行在內核模式),請求之後將被發送到Dokan文件系統驅動程序(dokan.sys )。 通過使用Dokan用戶模式庫文件(dokan.dll)提供的函數,文件系統應用程序能夠向文件系統驅動程序註冊回調函數。 文件系統驅動程序在收到請求後調用註冊的回調函數例程來響應請求。 回調函數例程的處理結果將返回給用戶程序。 例如:當Windows資源管理器請求創建一個目錄,請求“OpenDirectory”將發送到Dokan文件系統驅動程序,然後驅動程序將調用文件系統應用程序提供的OpenDirectory回調函數例程。 函數例程的處理結果作為OpenDirectory請求的響應返回給Windows資源瀏覽器。 如此一來,Dokan文件系統驅動程序就如同一個位於用戶程序和文件系統程序之間的代理程序。 使用Dokan庫的好處是,它允許程序員開發更安全也更容易調試的用戶空間文件系統。
二、Dokan SSHFS
  SSHFS(SSH文件系統)是一個文件系統客戶端程序,使用它可以將遠程服務器上的目錄掛載在本地直接訪問。 先前的版本用於輸出SFTP提供的目錄和文件,而當前的版本主要用於安裝有FUSE的系統上。 在用戶訪問服務器資源的過程中,數據通過SSH加密傳輸,安全而高效。
  Dokan是FUSE的Windows實現,使用Dokan SSHFS可以將Linux服務器上的目錄以網絡盤的形式掛載到本地使用,類似於Samba。 要使用Dokan SSHFS需要首先安裝Dokan Library,它們可以在Dokan官方網站下載。

How to repair and clone disk with ddrescue

  ddrescue  is a tool that can be used to repair and clone disks on a  Linux system . This includes hard drives, partitions, DVD discs, flas...