linux 下程序員專用搜索源碼用來替代grep的軟件ack(后來發現一個更快的: ag), 且有vim插件的


發現一個比ack更快更好用的:  https://github.com/ggreer/the_silver_searcher   , 使用時命令為ag,它是基於ack的代碼二次開發的,所有使用方法基本和ack差不多(包括命令行參數),但也小有區別。 

ubuntu 下安裝:  sudo apt-get install silversearcher-ag

ag man page:    https://www.mankier.com/1/ag

可以在 源碼(要搜索的目錄) 目錄建立一個 .ignore 文件來讓ag忽略不想搜索的文件,如:

$  cat ~/cloudkick/reach/.ignore:
*cough*
*.min.js 

ag example:

ag printf       :                         Find matches for "printf" in the current directory.

ag foo /bar/               :            Find matches for "foo" in path /bar/.

ag  -- --foo      :               Find matches for "--foo" in the current directory. (As with most UNIX command line utilities, "--" is used to signify that the remaining arguments should not be treated as options.)

ag -G cpio.c size :         在所有文件名為 *cpio.c* 的文件中搜索字串 size.        (-G --file-search-regex PATTERN,       Only search files whose names match PATTERN. 幫助中出現PATTERN項就代表必須使用正則式)

ag -G cpio.c -w size  : 在所有文件名為 *cpio.c* 的文件中搜索單詞 size. 

ag readme$  :          正則式搜索 readme$

ag .rb files/     :             在files目錄搜索含  .rb  的字串  (所有的 arb,   crb  等等)

ag  -Q  .rb files/     :     在files目錄搜索含  .rb  的字串  (只匹配 .rb,相當於正則式的  \.rb)

ag DHH -l   :                搜索含有單詞 DHH 的所有文件,且只打印處文件名

ag readme -l -G action   :   在所有文件名為 *action* 的文件中搜索字串 readme,且只打印處文件名

ag readme -l -G action$   :   在所有文件名為 *action 的文件中搜索字串 readme,且只打印處文件名

ps -e | ag forego    :   通過管道使用 ag

ag  readme -l -G action$ --pager "less -R"  :   在所有文件名為 *action 的文件中搜索字串 readme,且只打印處文件名,使用 less來分頁。(alias ag="ag $* --pager 'less -R'",這個可以一勞永逸

  

 

 

下面是 grep, ack, ag 的對比: 

grep, ack, or ag, which one should you use?

There’s no wrong answer. Each tool has its own strengths, and you should use whichever best fits your needs. This quick cheat sheet can help inform your decision:

grep

  • Available on all Unix-like systems by default, but not on Windows.
  • Everyone knows it, and should be used for scripting purposes.

ack

  • Very portable, runs on any system that runs Perl, including Windows
  • Ignores backup files, binary files, your VCS’s work files, and other unwanteds
  • True Perl regular expressions, not PCRE, because it’s written in Perl
  • Flexible output with the --output option
  • User-definable file types
  • Project-level configuration

ag

  • Very fast
  • Uses your VCS’s ignore files to know what to ignore
  • Searches compressed files
  • Better editor integration
  • Not as portable; Windows version is out of date

可以看出,ag無法自定義文件類型,即 ack 的 --type-set 選項。

 

 

 

 

ubuntu下要安裝ack-grep,因為在debian系中,ack這個名字被其他的軟件占用了。 sudo apt-get install ack-grep。

什么是ACK?

  1. http://betterthangrep.com
  2. ack is a tool like grep, optimized for programmers
  3. is written purely in Perl 5,takes advantage of the power of Perl's regular expressions.
  4. 作者在厭煩了不停的寫下面的這個查找命令之后,開發了ack這個工具
grep foo $(find . -name '*.pm' | grep -v .svn)

可以看的出來,ack誕生的目的就是要取代grep,從作者開發的初衷以及它官網的名字,另外它還有一個“可以替代99%grep的工作”這個口號。

ack 的 github地址:    https://github.com/petdance/ack2

ack 的 vim plugin 的地址:     https://github.com/mileszs/ack.vim

ack 的 官方幫助:  https://beyondgrep.com/documentation/ack-2.18-man.html

安裝

ubuntu下要安裝ack-grep,因為在debian系中,ack這個名字被其他的軟件占用了,使用 sudo apt-get install ack-grep.

如果你的程序安裝完成之后名字叫 ack-grep,是不是會嫌棄使用太麻煩了,可以這ubuntu下用下面的命令將它改成 ack:

$ sudo dpkg-divert --local --divert /usr/bin/ack --rename --add /usr/bin/ack-grep

 安裝完后,執行 (先用 ack --help-types 看看,只添加缺失的):

$  echo "--type-add=html:ext:shtml,xhtml" >> ~/.ackrc

將shtml和xhtml加入到html類型里。注意,ack每次執行命令的時候,會將 ~/.ackrc 里的參數都自動加到你這終端執行的命令里。

再將下面的添加進~/.ackrc

--color --pager=less -r

其中的 --color表示在通過管道的時候也始終保持顏色高亮,--pager是選用less -r作為pager。

特點

大家都說自己的東西好,因此ack官網列出了這工具的5大賣點:

  1. 速度非常快,因為它只搜索有意義的東西。
  2. 更友好的搜索,忽略那些不是你源碼的東西。
  3. 為源代碼搜索而設計,用更少的擊鍵完成任務。
  4. 非常輕便,移植性好。
  5. 免費且開源

better than grep?

先來看下grep的日常用法。

grep常用操作
  1. grep -r 'hello_world' # 簡單用法
  2. grep '^hello_world' . # 簡單正則
  3. ls -l | grep .py # 管道用法

一些參數:

-c(統記)/ -i(忽略大小)/ -h(不顯示名稱)/
-l(只顯文件名)/ -n(加行號)/ -v(顯示不匹配)

這些命令在Linux上的適用頻率是相當高的,尤其是你用vim做為IDE的話(當然這是說在不知道ack之前)。

ack功能划分

在記憶的時候大體上可以分為這幾個部分:

  1. Searching代碼搜索
  2. Search output搜索結果處理
  3. File presentation文件展示
  4. File finding文件查找
  5. File inclusion/exclusion文件過濾

下面對每一項給幾個簡單實用的例子。

基本用法:

  • -i           不區分大小寫
  • -f  --X         only prints the files that would be searched, without actually doing any searching, where “X” denotes the filetype (e.g., “--html”)
  • -n           does not descend into any subdirectories. 不進入子目錄進行遞歸搜索。
  • -w            only matches whole words。 搜索整個單詞,而不是字符匹配。
  • --type=noX    excludes certain filetypes from the search, where “X” denotes the filetype to be excluded (e.g., “--type=nophp” to exclude PHP files)

Searching

簡單的文本搜索,默認是遞歸的。

 

ack --help-types             # 打印所有type類型
ack "include|RTSP" . # ack 'pattern1|pattern2|pattern3' 可以搜索含有 pattern1 或者 pattern2 或者 pattern3 的行
ack-grep hello ack-grep -i hello ack-grep -v hello # 反向選擇,即過濾掉含 hello 的行 ack-grep -w hello ack-grep -Q 'hello*' ack -f --html # 打印類型是html的文件,不做具體的搜索,相當於find命令,html類型的文件大致包含: .html, .htm. 使用 ack -f --html -w index 方式是不對的,不能同時搜文件和文件內容。 ack -w --type=nojs css #查找不是js類型之外的其它文件,只要該文件含有單詞css ack -n "(^9999)|(^000)" #這種正則表達式和grep的類似,這里只是查找文件,不進入子目錄進行遞歸(-n),它顯示含有以9999或者000開頭的行 ack -g log --cc # -g代表只搜索文件(會遞歸進子目錄),這里的意思是搜索c類型的文件,其文件名相對路徑含有字符log,輸入如 *log*.c *log*.h 這樣的文件。 ack -g log --cc -w aa,這樣使用是不對的,不能同時搜文件和文件內容。
ack
--type-add=html:ext:shtml,xhtml #只影響當前的命令,必須配合搜索命令一起使用,如:ack --type-add=html:ext:shtml,xhtml --html -w body,或者 ack --type-add=html:ext:shtml,xhtml -f --html echo "--type-add=html:ext:shtml,xhtml" >> ~/.ackrc #這個可以將增加某類型的類型定義保存起來,以后每次使用ack都會生效。 --type-set=example:is:example.txt # 這個是改變或新建某類型的類型文件。 echo "--type-set=bashcnf:match:/.bash(rc|_profile)/" >> ~/.ackrc #這個是用正則式來定義類型參數,定義里一個叫bashcnf的類型,該類型匹配 .bashrc 或 .bash_profile 兩個文件。 ack 'string1|string2' #搜索string1或string2.

 

Search File

對搜索結果進行處理,比如只顯示一個文件的一個匹配項,或者xxx

ack-grep --line=1     # 輸出所有文件第二行

ack-grep -l 'hello'     # 搜索內容包含hello的所有文件,但是只打印其文件名,不打印匹配的文件內容行。

ack-grep -L 'print'     # 搜索內容不包含print的所有文件,但是只打印其文件名,不打印匹配的文件內容行。

File presentation

輸出的結果是以什么方式展示呢,這個部分有幾個參數可以練習下

ack-grep hello --pager='less -R'    # 以less形式展示
ack-grep hello --noheading      # 不在頭上顯示文件名
ack-grep hello --nocolor        # 不對匹配字符着色

File finding

沒錯,它可以查找文件,以省去你要不斷的結合find和grep的麻煩,雖然在linux的思想是一個工具做好一件事。

ack-grep -f hello.py    # 查找全匹配的文件,即文件名為hello.py的文件
ack-grep -g hello.py$    # 查找正則匹配文件,即 *hello.py 的所有文件
ack-grep -g hello  --sort-files     #查找然后排序

File Inclusion/Exclusion

文件過濾,個人覺得這是一個很不錯的功能。如果你曾經在搜索項目源碼是不小心命中日志中的某個關鍵字的話,你會覺得這個有用。

ack-grep --python hello    # 查找所有含有字串hello的python文件
ack-grep -G hello.py$ hello     # 查找匹配正則的文件, -G已經被 ack2 廢棄。

ack配置

也是一個相當贊的功能(配置文件為 ~/.ackrc),對grep了解不多,不知道grep有沒有同樣的東西。通過配置可以把你的個人習慣做為默認配置,比如我是Python程序員,那默認我要搜索的文件大多數必然是.py的文件。每次搜索時都要輸入:--python那就太無聊了。

另外還可以自己指定類型,通過--type-set=conf=.conf,指定一個.conf的文件形式,ack默認提供常見源碼的支持。你可以通過:ack-grep --help types查看它支持多少中類型的源碼,絕對有你不知道的語言。

下面是一個簡單的配置

# 設置排序
--sort-files
#設置文件過濾
--python
--html
--js
--conf
# 設置顯示
--noheading
# 定義新的文件類型
--type-set=conf=.conf
# 智能識別大小寫
--smart-case
# 設置以less形式展示,設定less參數
--pager=less -R -M --shift 5 -i

一些資源

  1. 官網文檔
  2. ack作者采訪
  3. ack-grep和grep對比
  4. 它還有對應的vim插件,使用方法和在終端上一樣。  網址:     https://github.com/mileszs/ack.vim

 

 

 

那么都有哪些優化那,看下其特點,有些特性正是grep缺少的(這是我自己總結的):

  • 為代碼搜索而定制 搜索時默認會忽略”.svn”,”.git”,”CVS”目錄,備份文件,二進制文件,core文件等,真是為源碼而生.如果覺得還不夠,可以在配置文件中設置.
  • 默認為遞歸搜索 源碼搜索一般確實都是遞歸的!
  • 可以指定搜索的源碼類型 可以通過參數--xxx來指定源碼類型,比如--python,--perl
  • 參數基本與grep一樣 大部分參數與grep保持一致
  • 存在vim插件(ack.vim),可以方便的通過vim來調用
  • ack比grep少一個一個字符.而且排序上ack要比grep靠前多了.

總之,grep為了搜索而生,ack為搜索源碼而生.

ack常用參數

  • -n,   不遞歸搜索子目錄
  • -l/L, 顯示匹配/不匹配的文件名
  • -c, 統計次數
  • -v, invert match
  • -w, 詞匹配
  • -i, 忽略大小寫
  • -f, 只顯示文件名,不進行搜索.

安裝配置

安裝

ubuntu:

apt-get install ack-grep -y 

配置

ack可以通過.ackrc來進行定制.比如下面舉例:

# 設置排序
--sort-files #設置文件過濾 --python --html --js --conf # 設置顯示 --noheading # 定義新的文件類型 --type-set=conf=.conf # 智能識別大小寫 --smart-case # 設置以less形式展示,設定less參數 --pager=less -R -M --shift 5 -i 

Warn: 以上並不是一個推薦的配置,只是舉例.個人基本沒有進行特別定制

vim與ack結合

在vim中進行多文件查找可以使用自帶的vimgrep命令,但是感覺有點別扭.可以集成ack到vim中,安裝插件即可.

搜索ack.vim插件進行安裝,並設置快捷鍵綁定.這里只是列出我的快捷鍵綁定.插件的具體安裝請參照官方文檔,推薦使用vundle來進行插件管理.

nmap <leader>ack :Ack nmap <leader>ackw :call Search_Word()<cr> function Search_Word() let w = expand("<cword>") execute "Ack " . w endfunction 

感慨

使用搜索工具有個矛盾點:

  • 使用者希望簡潔 使用者不確定或者為了方便才進行搜索,渴望簡潔.就像google桌面和360的桌面當想搜索的時候按兩下ctrl就調用出輸入口進行.
  • 程序希望提供精細化的條件指定 如果沒有精細化的條件指定,電腦負擔就加重了.最要命的是io負載,多人使用的服務器,如果有人隨意使用find,grep的話很可能導致其他人卡頓.一旦提供精確一點的條件,命令行輸入會非常麻煩.

例如在服務器上,我一般使用grep基本都會使用-F--include,這樣效率會高,但是寫起來麻煩.所以看到ack后會很高興的去試用,並轉換.

ack的設計目的上就明確了簡化grep,為了更好的搜索代碼.所以默認就會排除非代碼目錄文件.而且還提供了配置文件定制的方式.這很贊!

 

 

 

ack-grep [options] PATTERN [FILE...]

參數說明:
-a : 搜索所有文件(不管什么類型),但是要注意,某些文件是永遠都不會搜索的(除非在命令行中指定),比如備份文件。也就是說 -a 並非真的搜索所有文件
-i : 忽略大小寫
-v : 輸出不匹配的行
-h : 不輸出文件名

-H :  強制輸出文件名。(默認選項,但搜索單文件時,該選項不是默認的;除此之外,搜索但文件時,無法顯示行號,加上這個選項就能顯示行號。)
-l : 只輸出匹配的文件名

-L: 只輸出沒有匹配的文件

-f:   僅列出來會搜索哪些文件,不做真實的搜索

-G REGEXP:僅搜索匹配給定正則的文件
-g REGEXP:   -f -G REGEXP的縮寫

-c, --count: 覆蓋正常輸出,打印每個文件匹配文本的次數,沒有匹配的文件輸出0,可使用-l輸出匹配的文件。

-1: 只要搜索到第一次匹配就停止搜索

默認查找子目錄
示例:

ack-grep --line=1           # 輸出所有文件第二行
ack-grep -l 'hello'          # 包含的文件名
ack-grep -L 'print'           # 非包含文件名

ack-grep -f hello.py          # 查找全匹配文件
ack-grep -g hello.py$          # 查找正則匹配文件
ack-grep -g hello  --sort-files     #查找然后排序

ack-grep --python hello       #查找所有python文件
ack-grep -G hello.py$ hello       # 查找匹配正則的文件
ack     "\bg_.*?\b"                # 查找所有以 g_ 開頭的單詞(word), \b 是單詞邊界的意思,?跟在*后面表示非貪焚模式。見如下表的lisp正則式規則。
ack     "\w*g_.*?\w*"            # 查找含有 g_ 的單詞(word)
grep -R -P -n "[^\x00-\x7F]"       # 查找所有非ascii字符,查找中文尤其有用

 

另外可以修改~/.ackrc來指定ack的配置

 

lisp正則式規則 

 

字符

描述

\

將下一個字符標記為一個特殊字符、或一個原義字符、或一個 向后引用、或一個八進制轉義符。例如,'n' 匹配字符 "n"'\n' 匹配一個換行符。序列 '\\' 匹配 "\"  "\(" 則匹配 "("

^

匹配輸入字符串的開始位置。如果設置了 RegExp 對象的 Multiline 屬性,也匹配 '\n'  '\r' 之后的位置。

$

匹配輸入字符串的結束位置。如果設置了 RegExp 對象的 Multiline 屬性,也匹配 '\n'  '\r' 之前的位置。

*

匹配前面的子表達式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"等價於{0,}

+

匹配前面的子表達式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"等價於 {1,}

?

匹配前面的子表達式零次或一次。例如,"do(es)?" 可以匹配 "do"  "does" 中的"do" 等價於 {0,1}

{n}

n 是一個非負整數。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o

{n,}

n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o'o{1,}' 等價於 'o+''o{0,}' 則等價於 'o*'

{n,m}

m  n 均為非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個 o'o{0,1}' 等價於 'o?'。請注意在逗號和兩個數之間不能有空格。

?

當該字符緊跟在任何一個其他限制符 (*, +, ?, {n}, {n,}, {n,m}后面時,匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串,而默認的貪婪模式則盡可能多的匹配所搜索的字符串。例如,對於字符串 "oooo"'o+?' 將匹配單個 "o",而 'o+' 將匹配所有 'o'

.

匹配除 "\n" 之外的任何單個字符。要匹配包括 '\n' 在內的任何字符,請使用象 '[.\n]' 的模式。

(pattern)

匹配 pattern 並獲取這一匹配。所獲取的匹配可以從產生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在 JScript 中則使用 $0$9 屬性。要匹配圓括號字符,請使用 '\('  '\)'

(?:pattern)

匹配 pattern 但不獲取匹配結果,也就是說這是一個非獲取匹配,不進行存儲供以后使用。這在使用 "字符 (|) 來組合一個模式的各個部分是很有用。例如, 'industr(?:y|ies) 就是一個比 'industry|industries' 更簡略的表達式。

(?=pattern)

正向預查,在任何匹配 pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始。

(?!pattern)

負向預查,在任何不匹配 pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始 

x|y

匹配 x  y。例如,'z|food' 能匹配 "z"  "food"'(z|f)ood' 則匹配 "zood"  "food"

[xyz]

字符集合。匹配所包含的任意一個字符。例如,'[abc]' 可以匹配 "plain" 中的 'a'

[^xyz]

負值字符集合。匹配未包含的任意字符。例如,'[^abc]' 可以匹配 "plain" 中的'p'

[a-z]

字符范圍。匹配指定范圍內的任意字符。例如,'[a-z]' 可以匹配 'a'  'z' 范圍內的任意小寫字母字符。

[^a-z]

負值字符范圍。匹配任何不在指定范圍內的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a'  'z' 范圍內的任意字符。

\b

匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配 "never" 中的 'er',但不能匹配 "verb" 中的 'er'

\B

匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'

\cx

匹配由 指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。x 的值必須為 A-Z  a-z 之一。否則,將 c 視為一個原義的 'c' 字符。

\d

匹配一個數字字符。等價於 [0-9]

\D

匹配一個非數字字符。等價於 [^0-9]

\f

匹配一個換頁符。等價於 \x0c  \cL

\n

匹配一個換行符。等價於 \x0a  \cJ

\r

匹配一個回車符。等價於 \x0d  \cM

\s

匹配任何空白字符,包括空格、制表符、換頁符等等。等價於 [ \f\n\r\t\v]

\S

匹配任何非空白字符。等價於 [^ \f\n\r\t\v]

\t

匹配一個制表符。等價於 \x09  \cI

\v

匹配一個垂直制表符。等價於 \x0b  \cK

\w

匹配包括下划線的任何單詞字符。等價於 '[A-Za-z0-9_]'

\W

匹配任何非單詞字符。等價於 '[^A-Za-z0-9_]'

\xn

匹配 n,其中 n 為十六進制轉義值。十六進制轉義值必須為確定的兩個數字長。例如,'\x41' 匹配 "A"'\x041' 則等價於 '\x04' & "1"。正則表達式中可以使用 ASCII 編碼。.

\num

匹配 num,其中 num 是一個正整數。對所獲取的匹配的引用。例如,'(.)\1' 匹配兩個連續的相同字符。

\n

標識一個八進制轉義值或一個向后引用。如果 \n 之前至少 n 個獲取的子表達式,則 n 為向后引用。否則,如果 n 為八進制數字 (0-7),則 n 為一個八進制轉義值。

\nm

標識一個八進制轉義值或一個向后引用。如果 \nm 之前至少有 nm 個獲得子表達式,則 nm 為向后引用。如果 \nm 之前至少有 n 個獲取,則 n 為一個后跟文字 的向后引用。如果前面的條件都不滿足,若 n  m 均為八進制數字 (0-7),則 \nm 將匹配八進制轉義值 nm

\nml

如果 n 為八進制數字 (0-3),且 m  l 均為八進制數字 (0-7),則匹配八進制轉義值 nml

\un

匹配 n,其中 n 是一個用四個十六進制數字表示的 Unicode 字符。例如, \u00A9 匹配版權符號 (©)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM