危険な生活が好きなら、答えはeval
次のとおりです。
#!/bin/bash
COMMAND="pwd | awk '{print \"dir: \"\$1}'"
while true
do
echo $(eval $COMMAND)
sleep 1
done
なぜ危険に?で何が起こっているのかを制御するのは困難eval
です.2 倍に、ナイーブな (まして悪意のある) ユーザーからコマンド文字列を受け入れる場合です。また、コマンドを含む文字列を慎重に引用しなければならなかったことに注意してください。
質問のバージョン 2 が機能しなかったのはなぜですか?
COMMAND=pwd | awk '{print "dir: "$1}'
この行は、率直に言って、あなたが思っていることをしません。
COMMAND=pwd
これはパイプラインであり、最初の「コマンド」は、データを に送信しない空のコマンドの環境変数として扱われる文字列割り当てawk
です。完了後、値$COMMAND
は空の文字列になります (パイプラインで使用されるサブシェルとCOMMAND=pwd
、(空の) コマンドが実行されたときにのみ適用されるため) ため、ループは空の文字列を実行した結果をエコーします。も空の文字列です。したがって、空白の行。
これは私にとってはうまくいきますが、AWK の印刷出力にタブを追加する際に問題が発生しています。これはエスケープが原因だと思います。がある場合、との間にCOMMAND="ls -l | awk '{print \$8 \$9}'"
タブを挿入するにはどうすればよいですか?\t
$8
$9
痛い、うん!
$8
ソースのとの間にタブがある場合は、$9
それawk
を一般的な空白として扱い、出力に貼り付け$8
て$9
まとめます。出力でタブを取得するには、タブを含む引用符で囲まれた文字列\t
、または 2 つのフィールドの間に含まれる引用符で囲まれた文字列が必要です。またはprintf()
、適切なフォーマット文字列で a を使用します。
したがって、原則として、おそらく次のものが必要になります。
COMMAND='ls -l | awk '\''{printf "%s\t%s\n", $8, $9}'\'
ほとんどが理解しやすいので、文字列を一重引用符に切り替えました。一重引用符または二重引用符のどちらを使用しても、コマンド自体には両方が含まれているため、エスケープの方法について心配する必要があります。シーケンスは、'\''
一重引用符を一重引用符で囲まれた文字列に埋め込む方法です。最初の一重引用符は、現在の一重引用符で囲まれた文字列を終了します。バックスラッシュの一重引用符は一重引用符を追加し、最後の一重引用符は単一の文字列を再開します。最後のシーケンス'\'
は と書くこともできます'\'''
が、最後の 2 つの引用符は長さ 0 のシングル クォーテーション文字列なので、削除しました。
これにより、タブ付きの適切な出力が生成されます。次を実行して確認できます。
eval $COMMAND
は、すべてのecho $(eval $COMMAND)
慎重な間隔を完全に元に戻し、ファイルと時間のリスト全体を、各「単語」が次の単語とスペースで区切られた 1 行にフラット化します。
echo
次のようにして、間隔 (および改行) を強制的に尊重することで、この問題を回避できます。
echo "$(eval $COMMAND)"
eval $COMMAND
しかし、これは「なぜ just を使わないのか?」という疑問を提起します。
(テスト: bash 3.2.48 Mac OS X 10.7.4。)