web-dev-qa-db-ja.com

文字列のbashコマンドは、後で使用するときではなく、文字列を作成するときに実行されます

私は比較的シェルスクリプトに慣れていませんが、 lftpプログラム を使用するスクリプトをほぼ完成させました。私が問題を抱えているスクリプトの一部は、コマンドの長い文字列(;で区切られている)を作成するときです。

for var in something
do
    ...
    commands_to_run+="echo Result is `tail -n 1 $somefile`;"
done

私が気づいているのは、tailプログラム(バッククォートで囲まれている)がforループの反復時に実行されているが、スクリプトの後半でコマンドの文字列を呼び出すときに実行されていないことです。

残念ながら、$ somefileの内容は、この段階ではまだ検査する準備ができていません。文字列の作成中にではなく、必要なときにコマンドを実行するにはどうすればよいですか?

10
Ricky

これは少しトリッキーです。 Haukeが提供した情報は正確です。それは、ユースケースのためにそれを解析するだけの問題です。

最も簡単な方法は、_$_をエスケープしながら$()構文を使用して、定義時に$()で囲まれたコマンドを変数定義が実行しないようにすることです。ネストされたコマンドを実行するには、実際の実行時にシェルが最終的な結果を(evalを介して)再評価する必要があることに注意してください。

例を見る方がはるかに簡単なので、次の例を参考にしてください。

_for((i=0;i<10;i++)); do 
  date +%s.%N  # Print a timestamp (in format seconds.nanoseconds)
  test="echo \$(date +%s.%N)" # Save a command to do the same
  sleep 1      # Sleep for a second
  eval "$test" # Evaluate the command saved in variable 'test'
  echo         # Print a new line before the next iteration
done
_

上記の例の出力例を次に示します(1回の反復にトリミングされています)。

_1398832186.133661344
1398832187.139076728
_

各ループの2番目のタイムスタンプは、最初のループの約1秒後です。逆に、test定義の_$_をエスケープせずにevalを削除せずに同じテストを実行すると、2つのタイムスタンプはほぼ​​一致します。

ほとんどの状況でevalを使用する習慣を身につけないでください。しかし、これは私がそれを避けるための良い方法を知らない状況の1つです。うまくいけば、これが役立ちます。幸運を!

8
daBeamer

引用にはいくつかのレベルがあります。二重引用符(_"..."_)は、空白といくつかの特殊文字(_~_、_&_、_|_、_;_、...)を保護しますが、パラメーターの展開を妨げませんおよびコマンド置換。

単一引用符(_'_)または「危険な」文字の前にバックスラッシュが必要です。

一般的に:バッククォートの代わりに$(tail ...)の使用を検討する必要があります。バックティックは古い標準ですが、私たちは$()がほとんどの人に問題を引き起こさないほど古いと言っています。新しいバージョンは読みやすく、ネストすることができます。ここでsxのフォーマットの問題は言うまでもありません...

6
Hauke Laging