【问题标题】:Manipulate selected variable using AWK使用 AWK 操作选定的变量
【发布时间】:2014-09-22 09:46:58
【问题描述】:

我有一个尝试使用 AWK 操作的 SQL 文件。我有以下行在VALUES 上拆分我的SQL 文件,因为我想以不同的方式处理该字段之前和之后的文本。

原始文件如下所示:

INSERT INTO `drt_mig_user`.`parametric_object`(`id`, `active`, `priority`, `createdatetime`, `lastupdatedatetime`, `discriminator`) VALUES ('10085', '1', NULL, '2014-09-19 16:18:39', '2014-09-19 16:18:39', 'gate')

我的 AWK 代码:

cat file.txt | awk -F'VALUES' '{printf("$this->addSql(\"%sVALUES%s\");\n", $1, $2)}'

产生这个:

$this->addSql("INSERT INTO `drt_mig_user`.`parametric_object`(`id`, `active`, `priority`, `createdatetime`, `lastupdatedatetime`, `discriminator`) VALUES ('10085', '1', NULL, '2014-09-19 16:18:39', '2014-09-19 16:18:39', 'gate') ");

现在我需要做的就是删除 drt_mig_user 并从整个第一个变量 $1 周围删除反引号,使其看起来像这样:

$this->addSql("INSERT INTO parametric_object(id, active, priority, createdatetime, lastupdatedatetime, discriminator) VALUES ('10085', '1', NULL, '2014-09-19 16:18:39', '2014-09-19 16:18:39', 'gate') ");

有没有办法像这样以不同的方式操作变量?

【问题讨论】:

  • 第一个变量中没有单引号 ('),而是有反引号 (`)。尽管您确实说过您的实际输入 looks something like this 所以这是您发布的示例输入实际上不是您的真实输入的一种方式吗?请发布在所有重要方面与您的真实输入完全相同的示例输入。
  • 你说的很对,我现在就编辑答案和问题

标签: linux awk text-manipulation


【解决方案1】:

要从您发布的输入中获得您想要的输出,只需:

$ awk -F'VALUES' '{gsub(/drt_mig_user`\.|`/,"",$1); printf("$this->addSql(\"%sVALUES%s\");\n", $1, $2);}' file
$this->addSql("INSERT INTO parametric_object(id, active, priority, createdatetime, lastupdatedatetime, discriminator) VALUES ('10085', '1', NULL, '2014-09-19 16:18:39', '2014-09-19 16:18:39', 'gate')");

如果您在 $1 中有单引号,只需将 gsub 正则表达式更改为

/drt_mig_user`\.|[\047`]/

【讨论】:

    【解决方案2】:

    您可以在结果打印之前对其进行 gsub。答案是:

    awk -F'VALUES' '{gsub(/`/,"",$1); gsub("drt_mig_user.", "", $1); printf("$this->addSql(\"%sVALUES%s\");\n", $1, $2);}'
    

    产生所需的:

    $this->addSql("INSERT INTO parametric_object(id, active, priority, createdatetime, lastupdatedatetime, discriminator) VALUES ('10085', '1', NULL, '2014-09-19 16:18:39', '2014-09-19 16:18:39', 'gate') ");
    

    最初我试图转义单引号而不是反引号,因为我混淆了这两者,任何寻找答案的人都应该查看this SO answer

    【讨论】:

    • 忽略那个答案。在 awk 脚本中包含单引号的简单方法是用 \047 表示它们,例如awk 'BEGIN{print "there\047s one"}' 而不是用 awk 'BEGIN{print "there'"'"'s one"}' 在 awk 和 shell 之间来回跳转。这两个都将打印there's one。当然,更简单的方法是将您的 awk 脚本放在一个文件中,并在需要它们的地方使用文字单引号,然后使用 awk -f script ... 执行它,因为这只是您使用单引号分隔脚本的事实导致首先是问题。
    • 谢谢,我会试试\047
    • 正如我在您问题下方的评论中提到的那样,您发布的示例输入使用反引号而不是单引号,因此无论如何处理单引号实际上是无关紧要的。另外:您应该删除此答案并编辑您的问题以包含任何相关信息。
    • @jaypal 明白了,当不在正则表达式上下文中时,这没什么大不了的,因为无论如何你都在使用字符串,但是你不得不使用字符串分隔符而不是正则表达式分隔符来做类似的事情$0 ~ "there" q "s one" 而不是 /there\047s one/ 然后它成为一个问题,因为你必须考虑字符串经过的双重解析,所以如果文本的其余部分包含转义字符,你必须对它们进行双重转义,如果这是从文件中读取或从变量中填充它会很快变得混乱。我发现始终使用\047 是最简单的。
    • @EdMorton 是的,这是有道理的。
    【解决方案3】:

    以上脚本适用于给定的情况。

    如果您想要一个适用于所有情况的标准脚本,那么您可以使用以下脚本。它不会替换 $1 中的所有点(.)

    awk -F'VALUES' '{gsub(/`|drt_mig_user../,"",$1); printf("$this->addSql(\"%sVALUES%s\");\n", $1, $2);}' file.txt
    

    【讨论】:

      【解决方案4】:

      如果你愿意,你也可以为此使用一个简单的循环

      while read query do
          first_part_temp=$( echo ${query} | awk -F 'VALUES' '{print $1}')
          second_part=$(echo ${query} | awk -F 'VALUES' '{print $2}' file.txt)
          first_part=$(echo $first_part_temp | sed s/\`//g | sed s/drt_mig_user.//g)
          echo "\$this->addSql(\"${first_part} VALUES ${second_part} \");" >> output.txt
      done < file.txt
      

      或者如果你想使用单行,那么你可以使用:

      awk -F'VALUES' '{gsub(/`|drt_mig_user|\./,"",$1); printf("$this->addSql(\"%sVALUES%s\");\n", $1, $2);}' file.txt
      

      【讨论】:

      • 上面的 shell 脚本有很多 bug(read 的使用不正确、没有设置 IFS、未引用的变量等),效率低下,而且无论如何都是完全错误的方法。 awk 脚本还不错,但会删除 $1 中的每个 . 而不仅仅是 drt_mig_user 之后的那个,这对于这一特定的 1 行输入很好,但通常可能不受欢迎。
      猜你喜欢
      • 1970-01-01
      • 2023-02-22
      • 2017-03-05
      • 2019-01-17
      • 1970-01-01
      • 2017-03-18
      • 1970-01-01
      • 1970-01-01
      • 2019-07-20
      相关资源
      最近更新 更多