2010-05-10 88 views
2

嘿,我試着寫一個littel bash腳本。這應該複製一個目錄和其中的所有文件。然後它應該在這個拷貝的目錄中搜索每個文件和目錄中的字符串(例如@ForTestingOnly),然後保存行號。然後它應該繼續計數每個{和}一旦數字是等於它應該保存行號碼。 =>它應該刪除這兩個數字之間的所有行。 我想製作一個搜索所有這些註釋的腳本,然後刪除這個ano之後的方法。 THX的幫助......bashscript文件搜索和替換!

到目前爲止我有:

echo "please enter dir" 
read dir 
newdir="$dir""_final" 
cp -r $dir $newdir 
cd $newdir 

grep -lr -E '@ForTestingOnly' * | xargs sed -i 's/@ForTestingOnly//g' 

現在使用grep我可以搜索並替換@ForTestingOnly ANOT。但我想刪除這個和下面的方法...

+0

你應該明確地提一下爲什麼用「java」標籤標記這個問題,我只能懷疑@ForTestingOnly是一個Java註釋... – bobah 2010-05-10 16:34:18

+1

小心發佈你到目前爲止的內容嗎? – 2010-05-10 16:34:28

+0

這將是非常容易做到這一點*幾乎*正確的,因爲你描述它,但要小心諸如評論或字符串文字裏面的「}」字符...... – 2010-05-10 16:42:34

回答

2

試試這個。儘管如此,在評論和文字方面卻忽略了大括號,因爲David Gelhar警告過。它只找到並刪除第一次出現的「@ForTestingOnly」塊(假設只有一個)。

#!/bin/bash 
find . -maxdepth 1 | while read -r file 
do 
    open=0 close=0 
    # start=$(sed -n '/@ForTestingOnly/{=;q}' "$file") 
    while read -r line 
    do 
     case $line in 
      *{*) ((open++)) ;; 
      *}*) ((close++));; 
      '') : ;; # skip blank lines 
       *) # these lines contain the line number that the sed "=" command printed 
       if ((open == close)) 
       then 
        break 
       fi 
       ;; 
     esac 
      # split braces onto separate lines dropping all other chars 
      # print the line number once per line that contains either { or } 
    # done < <(sed -n "$start,$ { /[{}]/ s/\([{}]\)/\1\n/g;ta;b;:a;p;=}" "$file") 
    done < <(sed -n "/@ForTestingOnly/,$ { /[{}]/ s/\([{}]\)/\1\n/g;ta;b;:a;p;=}" "$file") 
    end=$line 
    # sed -i "${start},${end}d" "$file" 
    sed -i "/@ForTestingOnly/,${end}d" "$file" 
done 

編輯:刪除一個呼叫sed(註釋掉和更換幾行)。

編輯2:

這裏的主要sed線的故障:

sed -n "/@ForTestingOnly/,$ { /[{}]/ s/\([{}]\)/\1\n/g;ta;b;:a;p;=}" "$file" 
  • -n - 只有明確要求
  • /@ForTestingOnly/,$當打印線 - 從包含該行「@ ForTestingOnly「到文件末尾
  • s/ .../... /g執行全局(每行)替代
  • \(... \) - 捕捉
  • [{}] - 替代什麼被抓獲加上一個換行符
  • ta - - 出現在列表bewteen方括號
  • \1\n的字符,如果分支標籤爲「a」
  • b - 分支(無標籤意味着「結束並再次開始下一行的每行週期) - 該分支作爲ta的」其他「功能,我本可以使用T代替ta;b;:a,但sed一些版本不支持T
  • :a - 標籤「一」
  • p - 打印線(實際上,打印模式緩衝區現在由可能有多個線路用「{ 「或‘}’上各一個)
  • = - 打印輸入文件

第二sed命令簡單地說,刪除開始於具有目標串和結束一個行的當前行號在...處由while循環找到的線。

我頂部的sed命令說我找到目標字符串並打印它的行號並退出。因爲主要的sed命令正在照顧在正確的地方開始,所以這條線是沒有必要的。

內部while循環查看主sed命令的輸出並增加每個大括號的計數器。當計數匹配時,它停止。

外部的while循環遍歷當前目錄中的所有文件。

+0

okey,但現在我喜歡對給定目錄中的所有文件執行此操作。並且sed有一些未知的命令:','不知道爲什麼...... – D3orn 2010-05-10 19:09:18

+0

'find'會將每個文件提供給進程。我不知道爲什麼這個逗號不起作用。你使用的是什麼版本的「sed」以及什麼操作系統和版本?我編輯了腳本,因爲我注意到我可以做出的輕微改進。 – 2010-05-10 19:41:41

+0

我正在使用Ubuntu 10.04我正在嘗試腳本,後來ony非常好的工作thx現在很多瞭解腳本中的每一行都很好^^ * * *等清除,但是sed命令我沒有得到^^歡呼s – D3orn 2010-05-10 19:56:57

0

我修復了舊版本中的錯誤。新版本有兩個腳本:一個awk腳本和一個bash驅動程序。

的驅動程序是:

#!/bin/bash 

AWK_SCRIPT=ann.awk 

for i in $(find . -type f -print); do 
    while [ 1 ]; do 
     cmd=$(awk -f $AWK_SCRIPT $i) 
     if [ -z "$cmd" ]; then 
      break 
     else 
      eval $cmd 
     fi 
    done 
done 

新的awk腳本是:

BEGIN { 
# line number where we will start deleting 
start = 0; 
} 

{ 
     # check current line for the annotation 
     # we're looking for 
     if($0 ~ /@ForTestingOnly/) { 
       start = NR; 
       found_first_open_brace = 0; 
       num_open = 0; 
       num_close = 0; 
     } 

     if(start != 0) { 
       if(num_open == num_close && found_first_open_brace == 1) { 
         print "sed -i \'\' -e '" start "," NR " d' " ARGV[1]; 
         start = 0; 
         exit; 
       } 
       for(i = 1; i <= length($0); i++) { 
         c = substr($0, i, 1); 
         if(c == "{") { 
           found_first_open_brace = 1; 
           num_open++; 
         } 
         if(c == "}") { 
           num_close++; 
         } 
       } 
     } 
} 

設置驅動程序中的路徑awk腳本,然後運行在根目錄的驅動程序。

+0

用'$()'替換反引號。 [這是爲什麼。](http://mywiki.wooledge.org/BashFAQ/082) – 2010-05-10 19:47:04

+0

ty, 如果您仍然遇到find命令嘗試 $ find。 -type f -print – Jay 2010-05-10 19:50:27

+0

我剛在程序中發現一個錯誤。如果一個文件包含多個要刪除的註釋,它將不起作用。這是因爲一旦sed刪除第一個註釋,第二行的#s將改變無效下一個sed命令。您將不得不將程序更改爲僅爲每個文件生成一個sed命令,然後重新運行整個事件,直到awk scrip不產生輸出。 – Jay 2010-05-10 20:28:58