以下の例を何で説明することができますが、曲芸に過度に言及せずにこの問題を解決する方法は何ですか?$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
議論を見せず、問題を引き起こしません。