行の先頭に「sudo」と入力すると、残りのコマンドにも適用されますか?

行の先頭に「sudo」と入力すると、残りのコマンドにも適用されますか?

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つの部分からなるパイプを認識し、開始するsudocatにパイプを設定します。シェルはこれがfoo最終的に命令になることを全く知りません。シェルはfoo単なる引数なので、に渡す必要がありますsudo

上記の場合、次の 2 つのケースのいずれも発生しませんが、 、 をパラメータとして取ったり、1 つsudoのパラメータとして渡してもシェル構文に属するため、とにかくコマンド全体が期待どおりに動作しません。 、デフォルトでは、シェルは機能しなくても、シェルは実行されません。foo|foo2|foo3foo | foo2 | foo3|sudo


sudo以下を使用して複数のコマンドを実行する2つの方法:

解釈するにはシェルが必要です|。これは2つの基本的なアプローチにつながります。

  1. sudo foo | sudo foo2 | sudo foo3メインハウジング処理配管。
  2. sudo sh -c 'foo | foo2 | foo3'新しい高エンクロージャがダクトを処理します。

と同様&&および/または||置換または類似しています|

ケース2では、デフォルトのシェルが起動され、sudowhileはfoo | foo2 | foo3引数の1つにすぎません。これは何でも文字列にすることができ、sudo後で開始して引数として渡しますshfoo | 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、渡したシェルコードにバグがある場合もあります。バグが原因で、シェルが予期しない操作を実行する可能性があります。プロモートされたプロセスに予期しないタスクを実行させるのは非常に悪いことです。したがってfoofoo2およびを高めたいかもしれませんが、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は唯一のオプションです。


より広い視点

次のように動作する他のコマンドがありますsudonohup、、、、、...niceioniceunshare

それは事実でもechoあります。あなたはechoここにいるとは思わなかった。

echo foo | foo2 | foo3

|と残りを引数として使用します。シェルから取り出せばfooそれが全てです。ほとんど誰も驚かない。

any(?) シェルにecho組み込まれています。つまり、シェルの一部です。 「組み込み」は、シェルが外部echo実行ファイルを実行せずにエコー操作自体を処理しますが、組み込みは外部echoしかし、信号に関連するいくつかの微妙さがあります。)。

場合によっては異なる動作をする1つ以上のコマンドがあります。timeこれは別々の実行可能ファイルであり、これを呼び出すと質問のsudo文脈と同じように動作します。たとえば、次のようになります。

command time -p sleep 2 | sleep 4

アイドル状態のOSでは、2秒間リアルタイムで報告する必要があります(timestderrで印刷されるため、パイプにもかかわらずレポートを表示できます)。しかしBashtimeではキーワードこれは、Bashが後続のコンテンツを解析する方法を変更します。これは、追加のシェル作成による偏見なしにパイプライン全体(またはシェルループなどを含むシェルコードの断片)を測定できるように意図的に行われました。この試み:

# in Bash
time -p sleep 2 | sleep 4

レポートには4秒が表示されます。

比較するこの問題そして私の答え。

答え4

はい、しかしコマンドは;|またはで終わります。&&||

いいえ、すべての複雑なコマンド(例a|b:)やスクリプトでは機能しません。

関連情報