Bashスクリプトで複雑なコマンドを実行する

Bashスクリプトで複雑なコマンドを実行する

Bashスクリプトで次のコマンドを実行しようとしています。

rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`

似たようなことを試しています。

RM_CMD="$(rm -rf 'ls -t ${FOLDER}/other_folder | awk NR>5')"

後で関数で使用してコマンドを実際に実行したいと思います。

複数のバリエーションを試しましたが、常に失敗しました。ここで正しいアプローチは何ですか?

-編集する-

追加情報

私が次のようなことをしようとすると

RM_CMD="rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`"

コマンドをすぐに実行しようとしているようです。これは私の意図ではありませんが(後で実行するために正しいコマンドを保存したい)、正しい値をすべて取得します。つまり、空の値は1つもありません。

-編集2-

私は次のようにコマンドをできるだけ分けようとします。

LS_CMD="ls -t ${FOLDER}/other_folder"    
AWK_CMD="awk 'NR>5' ${LS_CMD}"    
RM_CMD="rm -rf '${AWK_CMD}'"

しかし、この問題が発生します。

+ ssh -t user@server 'rm -rf '\''awk '\''NR>5'\'' ls -t /full/path/to/folder/other_folder'\'''
bash: 5 ls -t /full/path/to/folder/other_folder: No such file or directory

ベストアンサー1

一般的に、このような質問に対する答えは、次を読むことです。BashFAQ#50:「コマンドを変数に入れようとしていますが、複雑な場合は常に失敗します!」。簡単な要約:変数は実行可能なコードではなくデータのためであるため、コードを挿入しようとするとあらゆる種類の問題に直面します。

しかし、この場合にはもう一つの重要な要素があります。を介してコマンドを実行することですssh。つまり、コマンドがリモートシステムに渡されることを意味します。データとして、リモートシステムのシェルによってコマンドとして解析されます。これは、スクリプト(ローカルシステム)の変数にコマンド(データ)を格納することが意味があることを意味します。

あなたが持っている最大の問題は、バックティックを使用する$( )か、一重引用符で囲まれていない場合は、内部コマンドがすぐに(ローカルシステムで)実行され、その出力が変数に保存されることです。これを防ぐには、変数を定義するときに関連文字をエスケープするだけです。

RM_CMD="rm -rf \$(ls -t '${FOLDER}/other_folder' | awk 'NR>5')"

$( )一般的に好まれるので、バックティックを代わりに使用しています。私が見るには、逆引用符と一重引用符をある時点で混同したようです。どちらも似ているようですが、まったく異なる効果があります。$( )本質的に同じことを行いますが、視覚的にあいまいではありません。

${FOLDER}また、ローカルコンピュータの変数なので、すぐに拡張する必要があるとします(スペースや他のシェルメタ文字が含まれている場合は、周囲に一重引用符を追加しました)。リモートシェル、目的の変更\"\${FOLDER|/other_folder\"。実際に${FOLDER}一重引用符自体が含まれている場合、一重引用符を囲むことは機能しません。この問題を解決する方法がありますが、ここでは心配しません。

変数の割り当てに一重引用符を使用することもできますが、コマンドで一重引用符を使用する際に問題が発生する可能性があります(一重引用符で囲まれた文字列内に一重引用符を入れ子にする明確な方法はありません)、ローカルでawkこれを行うためのきちんとした方法ありません。${FOLDER}機械を拡張してください。これは参照を混在させることで解決できますが、厄介です。

最後に、変数を使用するときは二重引用符で囲む必要があります。

ssh -t user@server "$RM_CMD"

...この特別な場合は問題ではありませんが、二重引用符ではなく変数参照にはあらゆる種類の問題がある可能性があるため、通常は二重引用符を使用することをお勧めします。

おすすめ記事