0

我想创建 scipt 以促进从 Hive 生成​​本地文本文件提取。这基本上是执行如下命令:

hive -e "SET hive.cli.print.header=true;SELECT * FROM dropme"|perl -pe 's/(?:\t|^)\KNULL(?=\t|$)//g'>extract/outbound/dropme.txt

虽然上面的工作就像一个魅力,但我发现通过参数化的以下脚本(非常简化)实现它非常有问题:

#!/bin/sh

TNAME=dropme
SQL="SELECT * FROM $TNAME"
echo $SQL
echo "SQL: $SQL"
EXTRACMD="hive -e \"SET hive.cli.print.header=true;$SQL\"|perl -pe 'BEGIN{if(defined(\$_=<ARGV>)){s/\b\w+\.//g;print}}s/(?:\t|^)\KNULL(?=\t|$)//g'>extract/outbound/$TNAME.txt"
echo "CMD: $EXTRACMD";
${EXTRACMD}

运行时我得到:Exception in thread "main" java.lang.NumberFormatException: For input string: "e"

我知道您可以打印文本或执行命令的方式有很多种。例如,该行echo $SQL打印了我目录中的文件列表:

SELECT file1.txt file2.txt file3.txt file4.txt FROM dropme

而下一个:echo "SQL: $SQL"给出了我想要的:SQL: SELECT * FROM dropme

echo "CMD: $EXTRACMD"打印(几乎)要执行的命令。几乎,正如我\t在 perl 代码中看到的那样:

CMD: hive -e "SET hive.cli.print.header=true;SELECT * FROM dropme"|perl -pe 'BEGIN{if(defined($_=<ARGV>)){s\w+\.//g;print}}s/(?: |^)\KNULL(?= |$)//g'>extract/outbound/dropme.txt

也许这仍然可以,但我想要的是能够将此命令复制并粘贴到(其他)终端并按照我放在顶部的命令执行。理想情况下,我希望该命令完全相同(所以在\t那里)

当我尝试执行它时,我遇到的最大问题是(${EXTRACMD}行)。我收到错误:

Exception in thread "main" java.lang.NumberFormatException: For input string: "e"…等等,因为 bash 在这里将每个“单词”都视为单个命令,这与此无关。我假设我什至不知道真正尝试运行的是什么(之前的打印尝试显然没有帮助)

我知道我有多种选择,例如:

  • 转义命令定义字符串中的特殊字符(就像我对双引号所做的那样)
  • 试验 echo 和$VAR,'$VAR'"$VAR"
  • 试验“${EXTRACMD}”或通过评估eval "${EXTRACMD}"
  • 试验shopt -s extglobset -f

但是由于组合的数量非常多,并且以我的小 bash 经验,我觉得最好在这里寻求良好的做法,所以我的问题是:

有没有办法先打印(复杂/复合外壳)命令,然后能够执行它(完全按照打印输出)?在这种情况下,它将从顶部打印确切的命令,然后以与手动将该输出复制到终端提示符并按相同的方式执行它Enter

4

1 回答 1

2

不要将命令构造为字符串。有关详细信息,请参阅http://mywiki.wooledge.org/BashFAQ/050

该页面还讨论了一种让 shell 告诉你它正在运行什么的内置方法(第 6 节)。

如果这不能满足您的要求,您也可以使用 bash 尝试使用printf %q\\n "${arr[*]}".

于 2014-10-31T11:02:44.383 回答