【问题标题】:Newbie: unix bash, nested if statement, results from a loop results from sql新手:unix bash,嵌套if语句,循环结果来自sql
【发布时间】:2017-01-05 02:29:33
【问题描述】:

这里的新手,请原谅我使用的任何令人困惑的措辞。 我的一项常见任务是获取名称列表并执行 MySQL 查询以在表中查找名称,并查看它们是否在我们的站点上“活动”。

一次执行此操作,我的 SQL 查询运行良好。然后,我想使用列出多个名称的文件中的循环来进行查询。这也很好用。

我将此查询循环添加到我的 bash 配置文件中,以便我可以通过键入以下内容快速完成任务:

$ ValidOnSite fileName

这很好用,我什至为我的进程添加了一个用法语句来提醒自己注意语法。以下是我所拥有的一切正常:

validOnSite() {


        if [[ "$1" == "" ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
                echo "Usage:"
                echo " $ validOnSite [filename]"
                echo " Where validOnSite uses specified file as variables in sql query:"
                echo " SELECT name, active FROM dbDb WHERE name=lines in file"
        else

                cat $1 | while read line ; do hgsql -h genome-centdb hgcentral -Ne "select name, active from dbDb where name='$line'" ; done

                fi

使用包含以下内容的文件“list.txt”:

nameA
nameB

然后我会输入:

validOnSite list.txt

list.txt 中的两个条目都符合我的查询条件并且在 sql 中找到。我的结果将是:

nameA 1
nameB 1

注意每个结果后面的“1”。我认为这是某种“是”状态。

现在,我在我的 list.txt 中添加了第三个名称,我知道这个名称在 sql 中不匹配。现在 list.txt 包含:

nameA
nameB
foo

当我再次为我的 3 行列表运行此命令时:

validOnSite list.txt

我的结果和我使用第一个版本的file.txt时一样,我看不到哪些行失败,我仍然只能看到哪些行是成功的:

nameA 1
nameB 1

我一直在尝试各种方法来添加一个嵌套的 if 语句,即“如果 $line 匹配,则回显“通过”,否则回显“失败”。

我不想在我的结果中看到“1”。使用具有 2 个匹配项和 1 个不匹配项的 file.txt,我希望我的结果是:

nameA pass
nameB pass
foo fail

或者更好的是,用绿色标记通过,用红色标记失败。

正如我所说,这里的新手... :)

任何指向正确方向的指针都会有所帮助。这是我最近一次悲伤的尝试,但我意识到我可能完全走错了方向:

validOnSite() {


        if [[ "$1" == "" ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
                echo "Usage:"
                echo " $ validOnSite [filename]"
                echo " Where validOnSite uses specified file as variables in sql query:"
                echo " SELECT name, active FROM dbDb WHERE name=lines in file"
        else

                cat $1 | while read line ; do hgsql -h genome-centdb hgcentral -Ne "select name, active from dbDb where name='$line'" > /dev/null ; done
 if ( "status") then
      echo $line "failed"
      echo $line "failed" >> outfile
else
     echo $line "ok"
     echo $line "ok" >>outfile
     clear
     cat outfile
     fi
fi

如果在我上一次尝试中有些东西看起来很疯狂,那是因为它是 - 我只是在谷歌上搜索并尝试尽可能多的东西,同时尝试学习。任何帮助表示赞赏,在长时间工作后我感到卡住了,但我很高兴能继续前进并找到解决方案!我认为我在理解标准输出方面缺少一些东西,并且对嵌套 if 也感到困惑。

注意:我不需要 outfile,但如果需要一个来完成目标也可以。单独的标准输出结果就足够了,并且是首选。

注意:hgssql 只是我们 MySQL 服务器的名称。 MySQL 部分工作正常,我正在寻找一种更好的方法来处理我的 bash 输出,我认为我缺少关于 stderr 的一些东西。由于我是新手,所以我正在寻找一个相当简单的答案!

【问题讨论】:

  • 我不熟悉hgsql,但我怀疑foo 的错误被写入stderr 而不是stdout(您仍然应该看到),但不会通过stdout 的简单重定向重定向到一个文件。第二个想法是hgsql 可能需要一个额外的选项(例如猜测--verbose 或类似的东西)来报告失败查询的结果。在 hgsql 文档中搜索一下,看看您是否发现这些方面有帮助。
  • 感谢您的评论。实际上,hgsql 只是我们 MySQL 服务器的名称。
  • 为什么不调用mysql -Bse "query..." 使用-B (batch) 模式会返回每个查询的结果。
  • @DavidC.Rankin 谢谢,我不知道 -Bse。我只是尝试使用它,但没有得到不匹配查询的结果。

标签: mysql bash if-statement stdout tty


【解决方案1】:

我猜,hgsql 是指一些允许执行 MySQL 查询的 Mercurial 扩展。我不知道hgsql 是如何工作的,但我知道MySQL 只返回匹配的行。但就 shell 脚本而言,即使匹配的行数为零,结果也是可能包含额外信息的字符串。例如,一些 MySQL 客户端可能会返回标头或类似“No rows found”的字符串,尽管这不太可能。

我将展示它是如何使用官方mysql 客户端完成的。我相信您将设法在 hgsql 的文档帮助下将其改编为以下示例。

if [ -t 1 ]; then
  red_color=$(tput setaf 1)
  green_color=$(tput setaf 2)
  reset_color=$(tput sgr0)
else
  red_color=
  green_color=
  reset_color=
fi


colorize_flag() {
  local color

  if [ "$1" = 'fail' ]; then
    color="$red_color"
  else
    color="$green_color"
  fi

  printf '%s' "${color}${1}${reset_color}"
}


sql_fmt='SELECT IF(active, "pass", "fail") AS flag FROM dbDb WHERE name = "%s"'

while IFS= read -r line; do
  sql=$(printf "$sql_fmt" "$line")

  flag=$(mysql --skip-column-names dbname -e "$sql")
  [ -z "$flag" ] && flag='fail'

  printf '%-20s%s\n' "$line" "$(colorize_flag "$flag")"
done < file

第一个块通过检查文件描述符1(标准输出)是否在终端上打开来检测脚本是否在交互模式下运行(参见help test)。如果在终端中打开,则脚本认为脚本是交互运行的,即标准输出直接连接到用户的终端,而不是通过管道等。对于交互模式,它在tput 命令的帮助下将变量分配给终端颜色代码。

colorize_flag 函数接受一个字符串 ($1) 并根据其值输出带有颜色代码的字符串。

最后一个块逐行读取file。为每一行构建一个 SQL 查询字符串 (sql) 并调用 mysql 命令,其中列名从输出中剥离。 mysql 命令的输出通过命令替换分配给flag。如果"$flag" 为空,则分配给'fail'$line 和彩色标志打印到标准输出。


您可以通过管道链接输出来测试非交互模式,例如:

./script | tee -a

我必须警告您,将 shell 变量传递给 SQL 查询通常是个坏主意,除非这些值被正确转义。而且流行的 shell 不提供任何工具来转义 MySQL 字符串。因此,请考虑使用 Perl、PHP 或任何能够安全地构建和运行查询的编程语言来运行查询。

另外请注意,就性能而言,最好运行单个查询然后在循环中解析结果集,而不是在循环中运行多个查询,prepared statements 除外。

【讨论】:

  • 非常感谢您的帮助。我非常感谢你的时间!我尝试在我的 SQL 查询之后直接粘贴您的代码(在行:cat $1 | while read line...等),但它没有用。我想这可能超出了我的理解,或许还有更简单的解决方案?
  • @Cath,你能把代码粘贴到某个地方吗?其实我以为你只用你的hgsql替换我代码中的mysql命令
【解决方案2】:

通过拼凑我所知道的几件基本知识,我找到了解决问题的方法。不优雅,但它现在工作得很好。我用输出创建了一个文件“[filename]Results”:

nameA 1
nameB 1

然后我剪下“1”并制作了一个新文件。然后,我将“[fileName]results”与 list.txt 进行了比较,以查看 file.txt 中存在哪些行但结果中不存在。

注意:我的 .zshrc 文件中有以下内容。

validOnSite() {


        if [[ "$1" == "" ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
                echo "Usage:"
                echo " $ validOnSite [filename]"
                echo " Where validOnSite uses specified file as variables in sql query:"
                echo " SELECT name, active FROM dbDb WHERE name=lines in file"
        else

        cat $1 | while read line ; do hgsql -h genome-centdb hgcentral -Ne "select name from dbDb where name='$line' and active='1'" >> $1"Pass"; done

autoload -U colors
colors
echo $fg_bold[magenta]Assemblies active on site${reset_color}
echo
cat $1"Pass"
echo
echo $fg_bold[red]Not active or not found on site${reset_color}
comm -23 $1 $1"Pass" 2> /dev/null
echo
echo

mv $1"Pass" ~cath/myFiles/validOnSiteResults
echo "Results file containing only active assemblies resides in ~cath/myFiles/validOnSiteResults"

fi
}

list.txt:

nameA
nameB
foo

我的意见:

validOnSite list.txt

我的输出:

Assemblies active on site (<--this font is magenta)

nameA
nameB

Not active or not found on site (<--this font is red)
foo


Results file containing only active assemblies resides in ~me/myFiles/validOnRRresults

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-01
    • 2015-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-30
    相关资源
    最近更新 更多