【问题标题】:How can you remove one line which contains the word SID in many files?如何删除许多文件中包含 SID 一词的一行?
【发布时间】:2010-11-19 03:41:12
【问题描述】:

如何删除许多文件中包含 SID 一词的一行?

我在 sed 和 tr 之间徘徊。但是,它们似乎都没有达到目的。 由于以下原因,我也希望有一些灵活性。

这个问题实际上更具挑战性。我还需要在某些文件中的匹配后删除一行,而在其他文件中删除前一行。一行有字符&,它决定是删除下面还是上面的一行,还是只删除匹配项。 可能最简单的方法是列出不同类型的文件,然后删除每个列表中具有不同代码的文件。

数据示例

这里&

    . "question_sent"
    . "&"                        // I do not want this line
    .  htmlspecialchars(SID)     // NOT wanted
    . "&"
    . "email="

这里没有&

    . "successful_registration&"
    . "SID="                    // Not wanted
    .  htmlspecialchars($SID)   // Not wanted
    . "&"                       // not wanted
    . "email="

字符 & 现在采用 HTML 编码,即 &

  if(isset($_GET['ask_question'])) {
      echo  ("<li id='ask_question_active'><a href='?ask_question&amp;"
          .  htmlspecialchars(SID)   // not wanted
          . "&amp;"                 // not wanted
          . "email=

【问题讨论】:

  • 我不太清楚要删除哪些“&”行。您是否希望第一个示例为 "question_sent\nhtmlspecialchars(SID)\nemail=" ?
  • 呼应 hlovdal,请通过编辑您的问题解释每种情况下应删除哪一行以及为什么。

标签: replace


【解决方案1】:

再次更新:我认为这修复了我之前发布的脚本中的错误。

#!/usr/bin/perl

use strict;
use warnings;

my $re_amp = qr/"&(?:amp;)?"/;
my $re_sid = qr/SID/;

while ( my $this = <DATA> ) {
    next unless $this =~ /\S/;

    if ( $this =~ $re_amp ) {
        $this = skip_while(\*DATA, $re_sid);
    }
    elsif ( $this =~ $re_sid ) {
        $this = skip_while(\*DATA, $re_sid, $re_amp);
    }

    print $this if defined $this;
}

sub skip_while {
    my ($fh, $re1, $re2) = @_;
    my $line;
    while ( $line = <$fh> ) {
        next if (defined $re1 and $line =~ $re1)
             or (defined $re2 and $line =~ $re2);
        last;
    }
    return $line;
}

__DATA__
handlers/handle_new_question.php-        . "question_sent"
handlers/handle_new_question.php-        . "&"                        // I do not want this line
handlers/handle_new_question.php:        .  htmlspecialchars(SID)   // NOT wanted
handlers/handle_new_question.php-        . "&"
handlers/handle_new_question.php-        . "email="

handlers/handle_registration.php-            . "successful_registration&"
handlers/handle_registration.php:            . "SID="                   // Not wanted
handlers/handle_registration.php:            .  htmlspecialchars($SID)   // Not wanted
handlers/handle_registration.php-            . "&"                  // not wanted
handlers/handle_registration.php-//            . "email="

views/ask_question_link.php-        if(isset($_GET['ask_question'])) {
views/ask_question_link.php-            echo  ("<li id='ask_question_active'><a href='?ask_question&amp;"
views/ask_question_link.php:                .  htmlspecialchars(SID)   // not wanted
views/ask_question_link.php-                . "&amp;"           // not wanted
views/ask_question_link.php-//                . "email=

输出:

C:\Temp> w
handlers/handle_new_question.php-        . "question_sent"
handlers/handle_new_question.php-        . "&"
handlers/handle_new_question.php-        . "email="
handlers/handle_registration.php-            . "successful_registration&"
handlers/handle_registration.php-//            . "email="
views/ask_question_link.php-        if(isset($_GET['ask_question'])) {
views/ask_question_link.php-            echo  ("<li id='ask_question_active'><a href='?ask_question&amp;"
views/ask_question_link.php-//                . "email=

【讨论】:

    【解决方案2】:

    当代码如此不一致时,我不会觉得运行全局搜索和替换是游戏。我会使用 grep/vim 来检查每一行,除非你真的要进行 10,000 次更改。要使用 grep/vim,步骤如下:

    1) 将以下内容添加到您的 .vimrc:

    " <f1> looks for SID in the current file
    map <f1> /\<SID\><CR>
    " <f2> goes to the next file
    map <f2> :next<CR><f1>
    
    " <f5> deletes only the current line, and goes to the next SID
    map <f5> dd
    " <f6> deletes the current line and the one above, and goes to the next SID
    map <f6> k2dd
    " <f7> deletes the current line and the one below, and goes to the next SID
    map <f7> 2dd
    " <f8> deletes the current line, and the one above AND the one below
    map <f8> k3dd
    

    2) 这个grep 命令将找到您需要更改的所有文件:

    grep -rl '\bSID\b' * > fix-these-files.txt
    

    您可能需要稍微调整一下,以确保它可以找到您需要更改的所有文件。在进行下一步之前确保它是正确的。

    3)使用vim打开所有需要修复的文件,如下:

    vim '+set confirm' '+/\<SID\>' $(cat fix-these-files.txt)
    

    4) 您现在应该打开了vim,并查看您需要更改的第一个文件中的第一个SID。使用以下步骤修复每次出现的 SID:

    • 如果只需要删除当前行,请按&lt;F5&gt;
    • 如果您需要同时删除以上行,请按&lt;F6&gt;而不是&lt;F5&gt;
    • 如果您需要同时删除下面一行,请按&lt;F7&gt;而不是&lt;F5&gt;
    • 如果您需要同时删除上面的行,请按&lt;F8&gt;而不是&lt;F5&gt;
    • &lt;F1&gt; 查找另一个出现的 SID 进行修复。
    • 当在当前文件中找不到 SID 时,请按 &lt;F2&gt; 转到下一个文件。

    当没有更多 SID 需要修复时退出 vim。

    5) 再次运行步骤 (2) 中的grep 命令,检查以确保一切顺利。应该没有搜索匹配项。

    6) 删除您在步骤 (1) 中添加到 .vimrc 的额外映射。

    警告:我没有测试过上面的步骤,如果你使用它们,小心你只做你需要的改变!

    【讨论】:

    • 这是一个很好的答案! - 它告诉我,有效地使用 Vim 可以帮助你很多。 - 你知道如何打开所有 grep 匹配到 Vim -windows 以便你可以直接进入匹配吗? - 伪代码:grep -l test *.php | vim
    • 'grep -l test *.php | vim -' (注意最后一个破折号)
    【解决方案3】:

    这不能用 tr 完成。可能可以使用 Sed,但我不太了解它,无法举个例子。我会使用 perl,然后我可能会引入一些状态变量,请参阅 this answer 了解我的意思的示例。可能我会使用状态single_ampersand_found(不要打印该行,如果下一行包含 SID,则忘记它,否则打​​印它)和SID_found(如果下一行包含并忘记该行)。


    更新:以下代码将抑制现在标记为“不想要”的所有行以及第一个示例中的第四行(即错误),但我认为它应该足以让您更正并适应您的需要。

    #!/usr/bin/perl -w
    use strict;
    use warnings;
    
    my $state = 0;
    my $state_ampersand_found = 1;
    my $state_SID_found  = 2;
    
    my $previous_line = "";
    
    while (my $line = <>) {
            chomp($line);
    
            if ($line =~ /"&/) {
                    if ($state == $state_ampersand_found) {
                            print $previous_line;
                    }
                    if ($state == $state_SID_found) {
                            $previous_line = "";
                            $state = 0;
                            next;
                    }
                    $state = $state_ampersand_found;
                    # remember current line, but do not print it (yet)
                    $previous_line = $line . "\n";
                    next;
            }
            if ($line =~ /SID/) {
                    $previous_line = "";
                    $state = $state_SID_found;
                    next;
            }
            $state = 0;
            print $previous_line;
            print $line, "\n";
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-23
      • 1970-01-01
      • 1970-01-01
      • 2020-09-09
      • 2015-09-14
      • 2012-12-18
      • 1970-01-01
      相关资源
      最近更新 更多