如何使此命令安全,并为引用的字符串工作

时间:2012-09-26 21:40:18

标签: perl bash ubuntu command

我发现(并改编了一下)使用正则表达式(和perl)编辑文件列表的命令。我把它放在一个名为cred的脚本文件中,因此我可以cred . england England在当前目录的所有文件中用england替换所有出现的England

find $1 -type f -exec perl -e 's/'$2'/'$3'/g' -p -i {} \;

它是邪恶强大的,已经有用 - 但危险,有缺陷。我想要...

  1. 首先预览更改(或至少操作文件),询问确认
  2. 使用比单个单词更长的字符串。我试过了cred . england 'the United Kingdom',但它失败了
  3. 我也会对其他(简短且令人难忘的,通用安装/可安装的osx和ubuntu)命令感兴趣来实现同样的目的。

    编辑:

    这是我到目前为止所做的改进......

    # highlight the spots that will be modified (not specifying the file)
    find $1 -type f -exec grep -E "$2" --color {} \;
    # get confirmation
    read -p "Are you sure? " -n 1 -r
    if [[ $REPLY =~ ^[Yy]$ ]]
    then
      # make changes, and highlight the spots that were changed
      find $1 -type f -exec perl -e "s/$2/$3/g" -p -i {} \;
      echo ""
      find $1 -type f -exec grep -E "$3" --color {} \;
    else
      echo ""
      echo "Aborted!!"
    fi
    

2 个答案:

答案 0 :(得分:3)

要处理带空格的字符串,请编写如下命令:

perl -e "s/$2/$3/g"

如果使用双引号,变量将在引号内展开。

要做一些事情,比如预览更改并要求确认,您需要一个更复杂的脚本。一件非常简单的事情就是首先运行find $1 -type f以获取所有文件的列表,然后使用read命令获取一些输入并决定是否应该继续。

答案 1 :(得分:1)

这是一个使用File :: Find的纯Perl版本。它相当长一点,但更容易调试,并做更复杂的事情。它适用于每个文件,可以更轻松地进行验证。

use strict;
use warnings;

use autodie;
use File::Find;
use File::Temp;

my($Search, $Replace, $Dir) = @ARGV;

# Useful for testing
run($Dir);

sub run {
    my $dir = shift;
    find \&replace_with_verify, $dir;
}

sub replace_with_verify {
    my $file = $_;
    return unless -f $file;

    print "File: $file\n";

    if( verify($file, $Search) ) {
        replace($file, $Search, $Replace);
        print "\nReplaced: $file\n";
        highlight($file, $Replace);
    }
    else {
        print "Ignoring $file\n";
    }

    print "\n";
}

sub verify {
    my($file, $search) = @_;

    highlight($file, $search);

    print "Are you sure? [Yn] ";
    my $answer = <STDIN>;

    # default to yes
    return 0 if $answer =~ /^n/i;
    return 1;
}

sub replace {
    my($file, $search, $replace) = @_;

    open my $in, "<", $file;
    my $out = File::Temp->new;

    while(my $line = <$in>) {
        $line =~ s{$search}{$replace}g;
        print $out $line;
    }

    close $in;
    close $out;

    return rename $out->filename, $file;
}

sub highlight {
    my($file, $pattern) = @_;

    # Use PCRE grep.  Should probably just do it in Perl to ensure accuracy.
    system "grep", "-P", "--color", $pattern, $file;    # Should probably use a pager
}