2

次のコードは正常に動作します

#!/bin/bash

while true; do
     echo $(pwd | awk '{print "dir: "$1}')
     sleep 1
done

しかし、このようにコマンドを変数に入れる必要があります。

#!/bin/bash                                                                     

COMMAND=pwd | awk '{print "dir: "$1}'
while true; do
     echo $($COMMAND)
     sleep 1
done

最初のスニペットは正常に実行され、次のように出力されますdir: /present/directory。2 番目のスニペットは空白行のみを出力します。それはなぜですか、どうすれば修正できますか?

私が使用したコマンドには意味がありません。パイプを使用する必要があり、これらのコマンドを選択してそれを示しました。

4

2 に答える 2

5

危険な生活が好きなら、答えは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。)

于 2012-08-27T01:16:01.210 に答える
0

一重引用符を使用すると、その中のすべてがリテラルになります。これは、$ が評価されないことを意味します。

ただし、2 番目の例では、$($COMMAND) と言って再評価を強制しています。これにより、'...$1' が再度処理されますが、今回は引用符なしです。それでは - ほら!できます!

これを修正するには、二重引用符を使用して " と ' を切り替えます (および \" 内で単一引用符を使用します)。

お役に立てれば、

J

于 2012-08-27T01:17:54.743 に答える