用于文件搜索和替换的bash脚本!

时间:2010-05-10 16:29:20

标签: bash scripting

嘿,我试着写一个小小的bash脚本。这应该复制一个目录和其中的所有文件。然后它应该在这个复制的目录中搜索每个文件和目录中的一个字符串(例如@ForTestingOnly),然后保存行号。然后它应该继续计算每个{和}一旦数字等于它应该保存线号。 =>它应该删除这两个数字之间的所有行。 我正在尝试创建一个搜索所有这些注释的脚本,然后删除直接在此ano之后的方法。 求救......

到目前为止,我有:

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。但我想删除这个和以下方法...

2 个答案:

答案 0 :(得分: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执行全局(每行)替换
  • \( ... \) - 捕获
  • [{}] - 列表中出现的字符位于方括号
  • 之下
  • \1\n - 替换捕获的内容加上换行符
  • ta - 如果进行了替换,则分支到标签“a”
  • b - 分支(没有标签意味着“到最后并再次为下一行开始每行循环) - 这个分支充当ta的”其他“,我可以已使用T代替ta;b;:a,但某些版本的sed不支持T
  • :a - 标签“a”
  • p - 打印行(实际上,打印模式缓冲区,现在可能包含多行,每行包含“{”或“}”)
  • = - 打印输入文件的当前行号

第二个sed命令只是说删除从具有目标字符串并以while循环找到的行结束的行开始的行。

我评论出的顶部的sed命令说找到目标字符串并打印它所在的行号并退出。该行不是必需的,因为主sed命令负责在正确的位置开始。

内部while循环查看主sed命令的输出,并为每个大括号递增计数器。当计数匹配时,它就会停止。

外部while循环遍历当前目录中的所有文件。

答案 1 :(得分: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脚本的路径,然后在根目录中运行驱动程序。