2013-01-09 25 views
0

我有一個分配給寫一個bash程序,如果我在下面輸入:如何在不使用find或grep -r的情況下僅使用bash grep內容文件?

-bash-4.1$ ./sample.sh path regex keyword 

,這將導致這樣的事情:

path/sample.txt:12 
path/sample.txt:34 
path/dir/sample1.txt:56 
path/dir/sample2.txt:78 

的數字是搜索結果中的行數。我完全不知道如何在bash中實現這一點,而不使用findgrep -r。我被允許使用grepsed,awk,...

+0

爲什麼你不能使用'grep'或'find'? – cegfault

+0

我想做一個課程,禁止我們使用那些...我絕對不知道我還能做什麼... – user1959859

+0

請幫助...我非常絕望... – user1959859

回答

2

將問題分解成部分。

  • 首先,您需要獲取要搜索的文件名。如何列出目錄及其子目錄中的文件? (提示:這是一個glob模式。)
  • 您需要遍歷文件。這是什麼形式的循環?
  • 對於每個文件,您需要依次從文件中讀取每一行。有一個內置的。
  • 對於每一行,您需要測試該行是否與指定的正則表達式匹配。這是一個構想。
  • 您需要維護一個文件中讀取行數的計數器,以便能夠打印行號。

在bash手冊中搜索globstar
參見https://unix.stackexchange.com/questions/18886/why-is-while-ifs-read-used-so-often-instead-of-ifs-while-read/18936#18936關於while read循環。


shopt -s globstar  # to enable **/ 
GLOBIGNORE=.:..   # to match dot files 
dir=$1; regex=$2 
for file in "$dir"/**/*; do 
    [[ -f $file ]] || continue 
    n=1 
    while IFS= read -r line; do 
    if [[ $line =~ $regex ]]; then 
     echo "$file:$n" 
    fi 
    ((++n)) 
    done <"$file" 
done 

這有可能是你的老師並沒有打算讓你來使用globstar功能,這是一個相對較新的除了來砸(出現在4.0版本)。如果是這樣,你需要編寫一個遞歸函數遞歸到子目錄中。

traverse_directory() { 
    for x in "$1"/*; do 
    if [ -d "$x" ]; then 
     traverse_directory "$x" 
    elif [ -f "$x" ]; then 
     grep "$regexp" "$x" 
    fi 
    done 
} 

把這個付諸實踐:

#!/bin/sh 
regexp="$2" 
traverse_directory "$1" 

後續練習:水珠圖案*省略文件名稱以一個.(點文件)。您也可以輕鬆地匹配點文件,也可以通過在.*上添加循環,即for x in .* *; do …。然而,當函數永久遞歸到.(以及..)時,它將該函數拋入無限循環。你怎麼能改變這個函數來處理點文件呢?

+1

哇,這是相當的一些東西。當我讀到你的時候,我立即取消了寫我的解決方案。謝謝! –

+0

非常感謝您的回覆! – user1959859

+0

我很抱歉,但我對這些非常新,所以我不明白那些真的......我的bash是3。2所以我沒有globstar上它...如果我使用第二個選項,我應該怎麼做traverse_directory函數?非常感謝! – user1959859