
Bashで行の先頭に入力すると、残りのsudo
コマンドにも適用されますか?
つまり、これは次のようになります。
sudo foo | foo2 | foo3
これと同等です:
sudo foo | sudo foo2 | sudo foo3
答え1
提供された最初のコマンドでのみ実行し、最初のパイプ以降の他のすべてのエントリが元のユーザーIDで実行されることを自信を持って確認する方法で、この役に立たsudo
ないコマンドチェーンを使用してこれを確認できます。
例 #1
$ sudo whoami > file1 | whoami > file2 | whoami > file3
その後、このファイルを表示すると、次cat
のユーザー名が表示されます。
$ cat file{1..3}
root
saml
saml
例 #2
ただし、サブシェルを実行する場合:
$ sudo sh -c 'whoami > file4 | whoami > file5 | whoami > file6'
その後、このファイルを表示すると、次cat
のユーザー名が表示されます。
$ cat file{4..6}
root
root
root
例 #3
sudo foo1 | sudo foo2 ...
の出力sudo foo1
がに提供されているので、あなたのコメントは動作しませんsudo foo2
。私のwhoami
例では、コマンドチェーンが何もしないことがわかります。
$ sudo whoami | sudo whoami | sudo whoami
root
最初は実行されたが、2番目と3番目は入力を受け入れる能力がなく、何もできなかった。代わりに、次のように書こうとしていると思います。
$ sudo whoami;sudo whoami;sudo whoami
root
root
root
これは、3つの異なるコマンドプロンプトで3回実行するのと同じです。またはこれ:
$ sudo whoami && sudo whoami && sudo whoami
root
root
root
しかし最後のことは絶対にしないでください。次のセクションに属します。
sudoを呼び出すあいまいな方法
これは最善の努力ではありませんが、複数のコマンドを実行するために使用する他の方法を見ることができますsudo
。私は彼らにここを見せようとしています教える必然的に他人を許可しないでくださいするそれらを!
方法1
$ echo "echo 1 > /proc/sys/vm/drop_caches" | sudo sh
どのように動作しますか?
sudoのため、二重引用符内のechoプログラムはrootとして実行されますが、echoの出力をルート専用ファイルにリダイレクトするシェルは依然としてユーザーとして実行されます。現在のシェルは起動する前にリダイレクトを実行しますsudo
。
方法#2
$ sudo tee /proc/sys/vm/drop_caches <<<1
どのように動作しますか?
このメソッドはtee
プログラムをrootとして実行しますここにある文字列sudo
コマンドを呼び出す前に実行されますtee
。
方法#3
# this way
$ sudo -s -- 'whoami'
# or this way
sudo -s -- sh -c 'whoami;whoami'
どのように動作しますか?
異なって見えるかもしれませんが、実際には同じことをしています。-s
スイッチを使用すると、sudo
単一のコマンドが実行されます。脱出口があるかどうかわからない。このようなことはうまくいきません。
# this
$ sudo -s -- 'whoami;whoami'
# or this
$ sudo -s -- 'whoami\;whoami'
ただし、マニュアルページを見ると、-s
スイッチはユーザーファイルエントリで定義されているシェルに単一のコマンドを渡すことがわかります/etc/passwd
。したがって、sh -c
実行されるコマンド文字列を「バックドア」する別のシェル()であるシェルを渡すことに関連する2番目の形式のトリックを使用します。
もっとたくさんありますが、ここでやめましょう。これは、あなたが理解している場合は何ができるかを示すためのものです。しかし、必ずしもゴミを互いに接続する必要はありません。他の人が理解してサポートできるように、コードプラグマを論理レベルに保つ必要があります。未来にあります。
答え2
いいえ、あなたの例foo
ではsudo
。高い特権ですべてのコマンドを実行するには、シェルを作成できます。
sudo sh -c 'foo | foo2 | foo3'
答え3
いいえ、なぜですか?
いいえ、sudo
残りのパイプラインには適用されません。この他の答えいくつかの例が示されていますが、その背後に隠れているメカニズムをすべて説明するわけではありません。
結論は、sudo
実行しているシェルに関係なく、単一の実行可能ファイルです。問題のコマンドは次のとおりです。
sudo foo | foo2 | foo3
シェルの場合も同様ですcat foo | foo2 | foo3
。シェルは3つの部分からなるパイプを認識し、開始するsudo
前cat
にパイプを設定します。シェルはこれがfoo
最終的に命令になることを全く知りません。シェルはfoo
単なる引数なので、に渡す必要がありますsudo
。
上記の場合、次の 2 つのケースのいずれも発生しませんが、 、 をパラメータとして取ったり、1 つsudo
のパラメータとして渡してもシェル構文に属するため、とにかくコマンド全体が期待どおりに動作しません。 、デフォルトでは、シェルは機能しなくても、シェルは実行されません。foo
|
foo2
|
foo3
foo | foo2 | foo3
|
sudo
sudo
以下を使用して複数のコマンドを実行する2つの方法:
解釈するにはシェルが必要です|
。これは2つの基本的なアプローチにつながります。
sudo foo | sudo foo2 | sudo foo3
メインハウジング処理配管。sudo sh -c 'foo | foo2 | foo3'
新しい高エンクロージャがダクトを処理します。
と同様&&
および/または||
置換または類似しています|
。
ケース2では、デフォルトのシェルが起動され、sudo
whileはfoo | foo2 | foo3
引数の1つにすぎません。これは何でも文字列にすることができ、sudo
後で開始して引数として渡しますsh
。foo | foo2 | foo3
内部文字列のみがsh
シェルコードとして解釈されます。
私が書いたが、sh -c
他のシェルを使うことができます。これは、一般がサポートしていない機能が必要な場合に特に適していますsh
。
賢明な選択をしなさい
一般に、私はシェルを取り付けた方法(方法2)を好みます。私の理由は次のとおりです。
1つだけで、
sudo
最大1回の資格情報を要求します。の場合、sudo … | sudo …
構成(sudoers
)によってそれぞれ個別sudo
に要求されることがあります。このツールは、同じ端末を使用する複数のインスタンスが互いに干渉せず、シェルが並行して実行されても、順番に要求するのに十分スマートです。悪い場合は、sudo … && sudo …
通常、2番目はsudo
(条件付きで)数時間後に開始する可能性があるため、2番目sudo
はパスワードを頻繁に尋ねないように設定した場合にも尋ねることができますsudo
。リダイレクトが含まれている場合は必要ありません。詐欺と
tee
(入力リダイレクトに代わるものではありませんsudo cat … | …
)。昇格したシェルがリダイレクトを処理できるようにすると、最も自然な方法で問題が解決されます。これは実際にはいくつかのファイルをrootとして開くことを前提としています。
一方、方法2にも欠点がある。場合によっては、方法 1 を選択することもできます。考慮すべき事項:
sudo some_shell -c …
新しい上昇したsome_shell
。バグがある場合もありsome_shell
、渡したシェルコードにバグがある場合もあります。バグが原因で、シェルが予期しない操作を実行する可能性があります。プロモートされたプロセスに予期しないタスクを実行させるのは非常に悪いことです。したがってfoo
、foo2
およびを高めたいかもしれませんが、foo3
それがすべてです。渡されるシェルコードは
sh -c
単一の引数でなければなりません。ほとんどすべての場合(確かにあなたの場合)、スペースやその他の文字を引用またはエスケープする必要があります。追加レベルの引用/エスケープは複雑さを増します。一般的に、すでに引用またはエスケープされた項目を適切に引用/エスケープする方法を知る必要があります。潜在的に役立つ可能性のあるリソース:Bashで一重引用符を使いやすくするか、コマンドライン全体をエスケープする方法は?
で始まるシェルは
sudo
メインシェルの変数にアクセスできません。変数のエクスポートは役に立つかもしれませんし、そうでないかもしれません。sudo
環境から変数を削除するように構成できます。メインシェルから展開された変数を別のシェルのコードに挿入すると、エラーが発生します。含める{}
、値が安全であることを知らない限り。私の言葉は一般的にこれが間違っているということです。sudo sh -c "foo \"$var\" | foo2"
変数を安全に渡す方法はいくつかあります。私はそれらをリストします(他のものがあるかもしれません):
var="$var" sudo -E sh -c 'foo "$var" | foo2' # may or may not work depending on sudoers and security policy sudo var="$var" sh -c 'foo "$var" | foo2' # may or may not work depending on sudoers and security policy sudo env var="$var" sh -c 'foo "$var" | foo2' sudo sh -c "foo ${var@Q} | foo2" # if the main shell is Bash sudo sh -c 'foo "$1" | foo2' sh "$var"
方法1は次のとおりです。
sudo foo "$var" | sudo foo2
簡単で安全です。
お客様が終了ステータス
foo
および/またはfoo2
その他に興味があると仮定した場合、sudo sh -c 'foo | foo2 | foo3'
お客様には提供されません。パイプを実行した後にこの情報を格納するシェル(例:Bash with it$PIPESTATUS[@]
)を使用しても、実行中の内部シェルからsudo
外部メインシェルに情報を確実に渡すことはマイナーな作業ではなく、退屈なコード(たとえば内部シェル)が必要ですします。と外殻のそれぞれ)。繰り返しますが、方法1は簡単です。
sudo foo | sudo foo2 | sudo foo3
それぞれ
sudo
(タスクが正常に完了する限り)は、foo*
そのコマンドの終了状態を渡します。これで必要なのは、メインシェルがパイプライン内の各コマンドの終了ステータスを知らせるだけです($PIPESTATUS[@]
メインシェルがBashの場合)。sudoers
制限された数のコマンドを実行できる場合は、sudo
そうでない可能性が高くなりますsh
(他の無制限のシェルまたはシェルのようなユーティリティと一緒に、そうでなければどのコマンドでも実行できるためsudo
)。foo
、およびが許可されているがシェルが許可しfoo2
ないfoo3
場合、sudo
方法1は唯一のオプションです。
より広い視点
次のように動作する他のコマンドがありますsudo
:nohup
、、、、、...nice
ionice
unshare
それは事実でもecho
あります。あなたはecho
ここにいるとは思わなかった。
echo foo | foo2 | foo3
|
と残りを引数として使用します。シェルから取り出せばfoo
それが全てです。ほとんど誰も驚かない。
any(?) シェルにecho
組み込まれています。つまり、シェルの一部です。 「組み込み」は、シェルが外部echo
実行ファイルを実行せずにエコー操作自体を処理しますが、組み込みは外部echo
(しかし、信号に関連するいくつかの微妙さがあります。)。
場合によっては異なる動作をする1つ以上のコマンドがあります。time
これは別々の実行可能ファイルであり、これを呼び出すと質問のsudo
文脈と同じように動作します。たとえば、次のようになります。
command time -p sleep 2 | sleep 4
アイドル状態のOSでは、2秒間リアルタイムで報告する必要があります(time
stderrで印刷されるため、パイプにもかかわらずレポートを表示できます)。しかしBashtime
ではキーワードこれは、Bashが後続のコンテンツを解析する方法を変更します。これは、追加のシェル作成による偏見なしにパイプライン全体(またはシェルループなどを含むシェルコードの断片)を測定できるように意図的に行われました。この試み:
# in Bash
time -p sleep 2 | sleep 4
レポートには4秒が表示されます。
比較するこの問題そして私の答え。
答え4
はい、しかしコマンドは;
、|
またはで終わります。&&
||
いいえ、すべての複雑なコマンド(例a|b
:)やスクリプトでは機能しません。