【问题标题】:bashscript for file search and replace!用于文件搜索和替换的 bash 脚本!
【发布时间】:2011-02-17 18:22:09
【问题描述】:

嘿,我尝试编写一个 littel 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。但是我喜欢删除这个和下面的方法...

【问题讨论】:

  • 你可能应该明确提到为什么用“java”标签标记这个问题,我只能怀疑@ForTestingOnly 是一个Java注释......
  • 想发布你目前拥有的东西吗?
  • 按照您的描述,几乎正确地做到这一点非常容易,但要注意 cmets 或字符串文字中的“}”字符......
  • 我不知道如何搜索一个单词并保存该行,然后搜索搜索 { 和 },然后删除...
  • 您始终可以使用自己喜欢的编程语言为单个文件编写解决方案,然后使用 find 命令递归地应用您的程序。

标签: bash scripting


【解决方案1】:

我修复了旧版本中的错误。新版本有两个脚本:一个 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 脚本的路径,然后在根目录中运行驱动程序。

【讨论】:

  • $() 替换反引号。 Here's why.
  • ty,如果您仍然无法使用 find 命令尝试 $ find 。 -type f -print
  • 我刚刚在那个程序中发现了一个错误。如果文件包含多个要删除的注释,它将不起作用。这是因为一旦 sed 删除了第一个注释,第二个注释的 #s 行将更改,从而使下一个 sed 命令无效。您必须将程序更改为每个文件只生成一个 sed 命令,然后重新运行整个程序,直到 awk 脚本不产生任何输出。
【解决方案2】:

试试这个。但是,正如 David Gelhar 所警告的那样,在 cmets 和字面量中使用大括号是不存在的。它只查找并删除第一次出现的“@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 的“else”,我可以使用 T 而不是ta;b;:a,但 sed 的某些版本不支持 T
  • :a - 标签“a”
  • p - 打印行(实际上,打印模式缓冲区,它现在可能由多行组成,每行带有“{”或“}”)
  • = - 打印输入文件的当前行号

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

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

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

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

【讨论】:

  • okey 但现在我喜欢对给定目录中的所有文件执行此操作。并且 sed 有一些未知的命令:',' 不知道为什么......
  • find 会将每个文件提供给进程。我不知道为什么逗号不起作用。您使用的是什么版本的 sed 以及什么操作系统和版本?我已经编辑了脚本,因为我注意到我可以做些小改进。
  • 我正在使用 Ubuntu 10.04 我稍后会尝试这个脚本 非常好的工作 thx 很多现在很高兴了解脚本中每一行的作用^^ { i> 等很清楚,但我没有得到 sed 命令^^欢呼 s
  • @D3orn:在带有 GNU sed 4.2.1 和 Bash 4.0.33(1)-release 的 Ubuntu 9.04 上运行,我没有收到该错误。这可能意味着变量“end”没有被设置,出于某种原因,但我看不出有什么原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-09
  • 2014-06-08
  • 2012-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多