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。