0

Hive からのローカル テキスト ファイルの抽出を容易にするために scipt を作成したいと考えています。これは基本的に以下のようなコマンドを実行することです:

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 extglobまたはの実験set -f

しかし、組み合わせの数が非常に多く、私の小さなbashの経験では、ここで良い練習をする方が良いと感じているので、私の質問は次のとおりです:

(複合/複合シェル) コマンドを最初に出力し、その後、(印刷された出力とまったく同じように) それを実行できるようにする方法はありますか? この場合、正確なコマンドを先頭から出力し、その出力を端末プロンプトに手動でコピーして を押すのと同じ方法で実行しますEnter

4

1 に答える 1