質問: ssh $ host $ fooとssh $ host "sudo su user -c $ foo"型構成の引用 sshを介して複雑なコマンドを発行することがよくあります。これらのコマンドには、awkまたはperlの1行へのパイプが含まれるため、結果として単一引用符と$が含まれます。私は引用を適切に行うための厳格な規則を理解することも、そのための適切なリファレンスを見つけることもできませんでした。たとえば、次のことを考慮してください。# what i'd run locally: cmd='pgrep -fl java | grep -i datanode | awk '{print $1}' # this works with ssh $host "$cmd": cmd='pgrep -fl java | grep -i datanode | awk '"'"'{print $1}'"'" (awkステートメントの余分な引用符に注意してください。)しかし、これをどのように機能させるのですか? ssh $host "sudo su user -c '$cmd'"?そのようなシナリオで見積もりを管理するための一般的なレシピはありますか?..
回答: 一般的な解決策の明確で詳細な説明については、 chris johnsenの回答 を参照してください。いくつかの一般的な状況で役立ついくつかの追加のヒントを提供します。単一引用符は、単一引用符以外のすべてをエスケープします。したがって、変数の値に一重引用符が含まれていないことがわかっている場合は、シェルスクリプトで一重引用符の間を安全に補間できます。su -c "grep '$pattern' /root/file" # assuming there is no ' in $pattern ローカルシェルがksh93またはzshの場合は、変数の単一引用符を'\''に書き換えることで対処できます。 (bashにも${foo//pattern/replacement}構文がありますが、単一引用符の処理は私には意味がありません。)su -c "grep '${pattern//'/'\''}' /root/file" # if the outer shell is zsh su -c "grep '${pattern//\'/\'\\\'\'}' /root/file" # if the outer shell is ksh93 ネストされた引用を処理する必要がないようにする別のヒントは、環境変数を介して文字列をできるだけ渡すことです。 sshとsudoはほとんどの環境変数を削除する傾向がありますが、通常はlc_*を通過させるように構成されています。これらは通常、使いやすさにとって非常に重要であり(ロケール情報が含まれているため)、セキュリティ上重要であるとは考えられないためです。lc_cmd='what you would use locally' ssh $host 'sudo su user -c "$lc_cmd"' ここでは、lc_cmdにはシェルスニペットが含まれているため、文字通り、最も内側のシェルに提供する必要があります。したがって、変数はすぐ上のシェルによって展開されます。最も内側の1つのシェルは"$lc_cmd"を参照し、最も内側のシェルはコマンドを参照します。同様の方法は、データをテキスト処理ユーティリティに渡すのに役立ちます。シェル補間を使用する場合、ユーティリティは変数の値をコマンドとして扱います。変数にsed "s/$pattern/$replacement/"が含まれている場合、/は機能しません。したがって、awk(sedではない)とその-vオプションまたはenviron配列を使用して、シェルからデータを渡します(environを使用する場合は、変数をエクスポートしてください) 。awk -vpattern="$pattern" replacement="$replacement" '{gsub(pattern,replacement); print}'