「sudo」の代わりに「sudo -i」を使用すると改行文字が削除されるのはなぜですか? [コピー]

「sudo」の代わりに「sudo -i」を使用すると改行文字が削除されるのはなぜですか? [コピー]

以下の例を何で説明することができますが、曲芸に過度に言及せずにこの問題を解決する方法は何ですか?$n実際の問題に注意が気になる場合に備えて、複数行のコマンド文字列をシミュレートするために使用しています。

~$ n=$'\n'; sudo -i echo "line1${n}line2${n}"
line1line2
~$

しかし、

~$ n=$'\n'; sudo echo "line1${n}line2${n}"
line1
line2

~$

答え1

straceで実行すると、sudo -i echo $'line1\nline2'Bashが次のように起動する方法が表示されます。

9183  execve("/bin/bash", ["-bash", "--login", "-c", "echo line1\\\nline2\\\n"], ...

strace文字列を表示すると、特殊文字はバックスラッシュエスケープで表示されるため、Bashが実際に引数として取得することはシェルの場合は連続行を表示する末尾のバックスラッシュで、バックスラッシュと-cその後のバックスラッシュは改行文字が削除されます。echo line1[backslash][newline]line2[backslash][newline]

いいえ-i、シェルを通さずに直接sudo実行します。echo

9189  execve("/bin/echo", ["echo", "line1\nline2\n"], ... 

ここでは文字通り改行文字を受け取りecho印刷echoします。


ここでのアイデアは、sudo次の事実に対応するためにエスケープシェルレイヤーを追加することですsh -c一つsudo独自のコマンドを別のパラメータとして使用する文字列です。

次のケースを比較してみてください。

sudoスペースを避けてください(これはコマンド名にすぎず、パラメータはありません!)。

$ sudo -i 'echo foo'
-bash: echo foo: command not found

sudoバックスラッシュをエスケープすると実際に動作します(Bashはechoバックスラッシュを処理しません)。

$ sudo -i echo 'foo\bar'
foo\bar

タブと同じ:

$ sudo -i echo $'foo\tbar'
foo     bar

ここではバックスラッシュの周りに余分な引用符がないので、Bashはシェルコマンドラインを処理するときにそれを削除します(bシェルの特殊文字ではなく、引用符は必要ありません。これはデフォルトでは同じですbash -c 'echo foo"b"ar')。

$ bash -c 'echo foo\bar'
foobar

問題は、バックスラッシュを使用して改行をエスケープすることができないことであり、sudoこれは考慮されていないようです。

とにかく、このような問題は必要な命令をファイルに保存してスクリプトで実行してみると、より簡単に参考にできるようです。

答え2

コマンド構造を変更できます。

echo "echo \"line1${n}line2${n}\"" | sudo -i bash -s

これはsudo議論を見せず、問題を引き起こしません。

関連情報