2010-05-10 94 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