【问题标题】:Use multiline regex on cat output在 cat 输出上使用多行正则表达式
【发布时间】:2018-05-22 11:18:12
【问题描述】:

我有以下文件queries.sql,其中包含许多查询,结构如下:

/* Query 1 */
SELECT cab_type_id,
       Count(*)
FROM   trips
GROUP  BY 1;

/* Query 2 */
SELECT passenger_count,
       Avg(total_amount)
FROM   trips
GROUP  BY 1;

/* Query 3 */
SELECT passenger_count,
       Extract(year FROM pickup_datetime),
       Count(*)
FROM   trips
GROUP  BY 1,
          2;

然后我编写了一个正则表达式,可以在文件中找到所有这些查询:

/\*[^\*]*\*/[^;]*;

我想要实现的目标如下:

  1. 使用正则表达式选择所有查询。
  2. 为每个查询添加前缀EXPLAIN ANALYZE
  3. 执行每个查询并将结果输出到新文件。这意味着,查询 1 将创建一个带有相应输出的文件 q1.txt,查询 2 创建 q2.txt 等。

我的主要挑战之一(没有问题,对吗?;-))是我对我必须使用的 linux bash 相当不熟悉。

我尝试了cat queries.sql | grep '/\*[^\*]*\*/[^;]*;',但没有返回任何内容。

所以解决方案可能如下所示:

count = 0
for query in (cat queries.sql | grep 'somehow-here-comes-my-regex') do
    count = $count+1
    query = 'EXPLAIN ANALYZE '+query
    psql -U postgres -h localhost -d nyc-taxi-data -c query > 'q'$count'.txt'

除了:那不起作用,我不知道如何使它起作用。

【问题讨论】:

  • 只是提示:grep 'somehow-here-comes-my-regex' queries.sqlcat queries.sql | grep 'somehow-here-comes-my-regex' 做同样的事情
  • 很高兴知道,谢谢!
  • @samwise,您当前的psql 命令不需要密码字符串吗?
  • 不,它是这样工作的。如果必须这样做,它只是在 docker 中作为基准。

标签: sql regex bash awk grep


【解决方案1】:

变量赋值时必须省略空格。

以下脚本会有所帮助。将其保存在文件中,例如:explain.sh,使用chmod 0700 explain.sh 使其可执行并以以下方式运行:./explain.sh query.sql

#!/bin/bash

qfile="$1"

# number of queries
n="$(grep -oP '(?<=Query )[0-9]+ ' $qfile)"

count=1
for q in $n; do
    # Corrected solution, modified after the remarks of @EdMorton
    qn="EXPLAIN ANALYZE $(awk -v n="Query $q" 'flag; $0 ~ n {flag=1} /;/{flag=0}' $qfile)"
    #qn="EXPLAIN ANALYZE $(awk -v n=$q "flag; /Query $q/{flag=1} /;/{flag=0}" $qfile)"
    # psql -U postgres -h localhost -d nyc-taxi-data -c "$qn" > q$count.txt
    echo "$qn" > q$count.txt
    count=$(( $count + 1 ))
done

首先,脚本包含一个参数(您的示例输入query.sql 文件)。它读出查询的数量并保存到变量n 中。然后在 for 循环中,它遍历查询编号并使用 awk 提取编号 n 查询并将 EXPLAIN ANALYZE 附加到开头。然后您可以使用所需的查询运行您的psql。在这里,我注释掉了 psql 部分。此示例脚本只为每个解释查询创建 qN.txt 文件。

更新:

awk 部分:可以使用 -v 标志在 awk 中使用 shell 变量。在这里,我们使用q shell 变量 的值创建一个awk 变量 nn 用于创建起始模式,即:查询 1。awk -v n="Query $q" 'flag; $0 ~ n {flag=1} /;/{flag=0}' $qfile 匹配 Query 1 和第一次出现的分号 (;) 之间的所有内容,不包括 query.sql 中的 Query 1 行。 $(...) 表示 bash 中的命令替换,因此我们可以将 shell 命令的输出保存到变量中。这里我们保存 awk 的输出,并在其前面加上 EXPLAIN ANALYZE 字符串。

Here 是关于 awk 模式匹配的一个很好的答案。

【讨论】:

  • 完美,谢谢!你介意简单解释一下qn="EXPLAIN ANALYZE $(awk -v n=$q "flag; /Query $q/{flag=1} /;/{flag=0}" $qfile)"这行吗?
  • 感谢@EdMorton 的评论。我打算使用:qn="EXPLAIN ANALYZE $(awk -v n=$q 'flag; $0 ~ n {flag=1} /;/{flag=0}' $qfile)".
【解决方案2】:

听起来这就是你要找的东西:

awk -v RS= -v ORS='\0' '{print "EXPLAIN ANALYZE", $0}' queries.sql |
while IFS= read -r -d '' query; do
    psql -U postgres -h localhost -d nyc-taxi-data -c "$query" > "q$((++count)).txt"
do

awk 语句将每个查询输出为一个以 NUL 结尾的字符串,shell 循环一次读取它,并在其上调用 psql。简单、健壮、高效等...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    • 2010-12-31
    相关资源
    最近更新 更多