【问题标题】:Script to migrate data from one source to another将数据从一个源迁移到另一个源的脚本
【发布时间】:2011-05-15 08:28:24
【问题描述】:

我有一个 .h 文件,其中包含这种格式的数据

struct X[]{
{"Field", "value1 value2 value"},
{"Field2", "value11 value12 value232"},
{"Field3", "x  y z"},
{"Field4", "a bbb s"},
{"Field5", "sfsd sdfdsf sdfs"};
/****************/
};

我有一个文本文件,其中包含我想在 .h 文件中用新值替换的值

value1   Valuesdfdsf1  
value2   Value1dfsdf  
value3   Value1_another  
sfsd     sfsd_ewew   
sdfdsf   sdfdsf_ew 
sdfs     sfsd_new   

生成的 .h 文件将包含上述文本文件中的替换内容。其他一切都保持不变。

struct X[]{
    {"Field1", "value11 value12 value232"},
    {"Field2", "value11 value12 value232"},
    {"Field3", "x  y z"},
    {"Field4", "a bbb s"},
    {"Field5", "sfsd_ewew sdfdsf_ew sdfs_new"};
    /****************/
    };

请帮我提供一个解决方案来使用 unix 工具完成它:awk、perl、bash、sed 等

【问题讨论】:

  • 字段-值对是否总是在同一行,值是否由单个空格分隔?
  • 空格/制表符,至少一个空格是肯定的
  • 不应该将第一行中的 value2 替换为 Value1dfsdf 吗?
  • 你是对的——它应该是。固定。
  • 您的值[123] 在您想要的结果示例中似乎没有被正确替换。

标签: bash perl sed scripting


【解决方案1】:

这个脚本应该可以工作
keyval是包含键值对的文件
filetoreplace是包含要修改的数据的文件
名为 changed 的文件将包含更改

#!/bin/sh
echo  

keylist=`cat keyval | awk '{ print $1}'`  


while read line   
do   

for i in $keylist  
do  


if echo $line | grep -wq $i; then  

    value=`grep -w $i keyval | awk '{print $2}'`  
    line=`echo $line | sed -e "s/$i/$value/g"`  
fi  

done  

echo $line >> changed  

done < filetoreplace

【讨论】:

    【解决方案2】:

    如果您的文件很大,这可能会有点慢。

    gawk -F '[ \t]*|"' 'FNR == NR {repl[$1]=$2;next}{for (f=1;f<=NF;++f) for (r in repl) if ($f == r) $f=repl[r]; print} ' keyfile file.h
    

    【讨论】:

      【解决方案3】:

      这是一个看起来很简单的程序:

      use strict;
      use warnings;
      use File::Copy;
      
      use constant {
          OLD_HEADER_FILE   => "headerfile.h",
          NEW_HEADER_FILE   => "newheaderfile.h",
          DATA_TEXT_FILE    => "data.txt",
      };
      
      open (HEADER, "<", OLD_HEADER_FILE) or
      die qq(Can't open file old header file ") . OLD_HEADER_FILE . qq(" for reading);
      
      open (NEWHEADER, ">", NEW_HEADER_FILE) or
      die qq(Can't open file new header file ") . NEW_HEADER_FILE . qq(" for writing);
      
      open (DATA, "<", DATA_TEXT_FILE) or
      die qq(Can't open file data file ") . DATA_TEXT_FILE . qq(" for reading); 
      
      #
      # Put Replacement Data in a Hash
      #
      
      my %dataHash;
      while (my $line = <DATA>) {
          chomp($line);
          my ($key, $value) = split (/\s+/, $line);
          $dataHash{$key} = $value if ($key and $value);
      }
      close (DATA);
      
      #
      # NOW PARSE THOUGH HEADER
      # 
      
      while (my $line = <HEADER>) {
          chomp($line);
          if ($line =~ /^\s*\{"Field/) {
              foreach my $key (keys(%dataHash)) {
                  $line =~ s/\b$key\b/$dataHash{$key}/g;
              }
          }
          print NEWHEADER "$line\n";
      }
      
      close (HEADER);
      close (NEWHEADER);
      copy(NEW_HEADER_FILE, OLD_HEADER_FILE) or
        die qq(Unable to replace ") . OLD_HEADER_FILE . qq(" with ") . NEW_HEADER_FILE . qq(");
      

      我可以通过使用map 使其更高效,但这会让它更难理解。

      基本上:

      • 我打开了三个文件,原始的 Header,我正在构建的新 Header,以及数据文件
      • 我首先将我的数据放入一个散列中,其中替换文本由原始文本键入。 (如果我愿意,可以反过来做。
      • 然后我浏览原始标题的每一行。 ** 如果我看到一条看起来像场线的线,我知道我可能需要更换。 ** 对于%dataHash 中的每个条目,我将$key 替换为$dataHash{$key} 替换值。我使用\b 来标记单词边界。这样,field11 不会被替换,因为我在该字符串中看到了 field1。 ** 现在我将这一行写回到我的新头文件中。如果我没有替换任何东西,我只是把原来的那行写回去。
      • 完成后,我将新头文件复制到旧头文件上。

      【讨论】:

      • 感谢您提供更易于使用的替代版本 :)
      【解决方案4】:
      #!/usr/bin/perl
      
      use strict; use warnings;
      
      # you need to populate %lookup from the text file
      my %lookup = qw(
          value1   Valuesdfdsf1
          value2   Value1dfsdf
          value3   Value1_another
          sfsd     sfsd_ewew
          sdfdsf   sdfdsf_ew
          sdfs     sfsd_new
      );
      
      while ( my $line = <DATA> ) {
          if ( $line =~ /^struct \w+\Q[]/ ) {
              print $line;
              process_struct(\*DATA, \%lookup);
          }
          else {
              print $line;
          }
      }
      
      sub process_struct {
          my ($fh, $lookup) = @_;
      
          while (my $line = <$fh> ) {
              unless ( $line =~ /^{"(\w+)", "([^"]+)"}([,;])\s+/ ) {
                  print $line;
                  return;
              }
              my ($f, $v, $p) = ($1, $2, $3);
              $v =~ s/(\w+)/exists $lookup->{$1} ? $lookup->{$1} : $1/eg;
              printf qq|{"%s", "%s"}%s\n|, $f, $v, $p;
          }
          return;
      }
      
      __DATA__
      struct X[]{
      {"Field", "value1 value2 value"},
      {"Field2", "value11 value12 value232"},
      {"Field3", "x  y z"},
      {"Field4", "a bbb s"},
      {"Field5", "sfsd sdfdsf sdfs"};
      /****************/
      };
      

      【讨论】:

        【解决方案5】:
        cat junk/n2.txt | perl -e '{use File::Slurp; my @r = File::Slurp::read_file("junk/n.txt"); my %r = map {chomp; (split(/\s+/,$_))[0,1]} @r; while (<>) { unless (/^\s*{"/) {print $_; next;}; my ($pre,$values,$post) = ($_ =~ /^(\s*{"[^"]+", ")([^"]+)(".*)$/); my @new_values = map { exists $r{$_} ? $r{$_}:$_ } split(/\s+/,$values); print $pre . join(" ",@new_values) . $post . "\n"; }}'     
        

        结果:

        struct X[]{
        {"Field", "value1 Value1dfsdf value"},
        {"Field2", "value11 value12 value232"},
        {"Field3", "x y z"},
        {"Field4", "a bbb s"},
        {"Field5", "sfsd_ewew sdfdsf_ew sfsd_new"};
        /****************/
        };
        

        代码解开:

        use File::Slurp;
        my @replacements = File::Slurp::read_file("junk/n.txt"); 
        my %r = map {chomp; (split(/\s+/,$_))[0,1]} @replacements; 
        while (<>) {
            unless (/^\s*{"/) {print $_; next;}
            my ($pre,$values,$post) = ($_ =~ /^(\s*{"[^"]+", ")([^"]+)(".*)$/); 
            my @new_values = map { exists $r{$_} ? $r{$_} : $_ } split(/\s+/, $values);
            print $pre . join(" ",@new_values) . $post . "\n";
        }
        

        【讨论】:

        • 天哪,我讨厌 Perl 的样子。以丑取权!接下来在我的学习列表中:)
        • @Morlock - 这不是 Perl 的样子。这就是 Perl one-liner 的外观 - 旨在尽可能少地占用字符串空间。以适当的 Perl 编码风格编写,上述代码中的绝大多数标点符号都消失了,留下了实际可读的程序。唯一看起来仍然像已编码的部分是正则表达式,它们在任何语言中看起来都是 100% 相同的。
        • 我可以,但是老兄,这是感恩节前的短短一天 :) 稍后作为一个单独的问题请求休息,Perl 标签上的某个人或我自己会很乐意提供帮助。只是现在没有:)
        猜你喜欢
        • 2023-02-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-21
        • 1970-01-01
        • 2012-12-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多