「修道-sシェルでコマンドを実行しますが、ワイルドカードやメタ文字は機能しません。

「修道-sシェルでコマンドを実行しますが、ワイルドカードやメタ文字は機能しません。

使用時sudo -s(以下"--shell"オプション)、「sudo」にコマンドを渡すことができます。この場合、ターゲットユーザとして「sudo」が起動したシェルでコマンドが実行されます。

(同様に、sudo -i次のように使用することもできます。「--ログイン」オプションまた、シェルを起動し、同様の方法で動作するコマンドも同様に受け入れます。 )

ほとんどの場合、シェルを介してsudoからコマンドを実行することが重要です。

  • 現在ユーザーがアクセスできないが、そのルートがアクセス可能なディレクトリでワイルドカードを使用している場合、ワイルドカードを正しく拡張するには、ルートシェルでコマンドを実行する必要があります。
  • パイプラインに接続された多くのコマンドを使用してパイプライン全体を実行します(|)。
  • などforのシェル組み込み機能を実行するときは、単一​​のスクリプトifの下で完全な小さなインライン「スクリプト」を実行するとsudo便利です。

出荷書類ビーチ"-s"オプション言った(強調):

環境変数SHELL(設定されている場合) で指定されたシェル、または呼び出すユーザーのパスワード・データベース項目として指定されたシェルを実行します。コマンドが指定されると、シェルのコマンドを介して渡されます。-氏オプション。コマンドを指定しないと、対話型シェルが実行されます。ほとんどのシェルは、インタラクティブセッションと比較してコマンドを指定した場合、動作が異なります。詳細については、シェルのドキュメントを参照してください。

つまり、sudo -sコマンドが渡されると、-c"script"を含む文字列を取得し、それをシェルスクリプトとして実行するoptionsを使用してシェルに渡されます。

このドキュメントでは、このオプションの使用方法については説明しません。「詳細については、シェルのドキュメントを参照してください」と言う以外は例を提供しません。これは、受信したコマンドが通過したことを意味します。まっすぐシェルのオプション-c。しかし、これは真実ではないことが判明しました。

複数の単語を含むシェルスクリプトを渡すと失敗します。

$ sudo -s 'ls -ld /var/empty'
/bin/bash: ls -ld /var/empty: No such file or directory

エラーメッセージは、文字列全体を単純なコマンドで実行しようとしていることを意味します...うーん、わかりました。スペースを追加すると機能しますか?はい、次のようなことが発生します。

$ sudo -s ls -ld /var/empty
drwxr-xr-x. 3 root root 18 Jul 12 21:48 /var/empty

しかし、シェルが実際に機能する方法はありません。ホームディレクトリへのショートカットなど、いくつかのメタ文字を使用してどのように機能するかを見てみ-cましょう。 sudo以外のシェルが拡張されないようにするには、引用符が~必要~です(この場合、/root予想とは異なり、root以外のユーザーのホームディレクトリに展開されます)。

$ sudo -s ls '~'
ls: cannot access '~': No such file or directory

~さて、だからこれはうまくいきません。エラー出力は、そこにリテラルを残すため、拡張が行われなかったことを意味するようです。

ワイルドカードはどうですか?また、動作しません。

$ sudo -s ls '/root/*.cfg'
ls: cannot access '/root/*.cfg': No such file or directory

どちらの場合も、コマンドを実行すると$SHELL -c正常に動作します。この場合は$SHELLbashなので、次のようになります。

$ sudo bash -c 'ls ~'
anaconda-ks.cfg
$ sudo bash -c 'ls /root/*.cfg'
/root/anaconda-ks.cfg

1つの例外は、変数がで動作しているようですsudo -s。たとえば、次のようになります。

$ sudo -s echo '$HOME'
/root

だから:

  • ここで何が起こっているのでしょうか?
  • ~または、に渡されたコマンドでワイルドカードとメタ文字(たとえば)が機能しないのはなぜですか?sudo -ssudo -i
  • $SHELL -cスクリプトが単一の文字列を使用して複数のパラメータを使用している場合、sudo -sスクリプトはパラメータからどのように組み合わせられますか?
  • シェルでコマンドを実行してこれを行う安定した方法は何ですかsudo

答え1

簡単に言うと:"--shell"または "--login"オプションに対してコマンドを実行すると、スペースを含むすべてのメタsudo文字を除くほとんどの文字がエスケープされます(バックスラッシュエスケープを使用)$

これにより、シェルを使用しようとするすべてのユースケースが中断され、ほとんどsudo -sの場合、シェルコマンドの実行が不適切になります。必要シェルコマンドで実行します。

代わりにor(または予想されるもの)sudo -sを使用してください。代わりに(ルートのシェルが再びbashであると仮定します。)sudo sh -c '...'sudo bash -c '...'$SHELLsudo -isudo bash -l -c '...'


見ているsudo ソースコード関連部分、次のスニペットがあります。

/* quote potential meta characters */
if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
    *dst++ = '\\';
*dst++ = *src;

このスニペットは、すべてのパラメータのすべての文字を繰り返します。文字が英数字、下線、ダッシュ、またはドル記号でない場合は、バックスラッシュでエスケープされます。

つまり、ワイルドカード文字*、などが、、、?[...]エスケープされます。\*\?\[...\]

また、、~のようなメタ文字は;、、でエスケープされます。|\~\;\|

スペースを含む文字列はls /rootにエスケープされますls\ /root

何らかの理由で$エスケープは例外であり、エスケープされていない状態sudo -s echo '$HOME'に保たれるため、機能します$。 (これは変数でのみ機能し、フォームでも機能しません${HOME}。この場合、中かっこがエスケープされ、式が中断されます。)


この引用の結果はほとんどの場合必要sudo -s <command>シェルをrootとして実行すると、次の形式の利点を実際に享受できません。

  • ワイルドカード文字はエスケープされ、ワイルドカード文字として使用できないため拡張されません。
  • パイプが|脱出して動作しないため、パイプは動作しません。
  • forと同じコマンドはif通常使用するために必要であり;、このコマンドもエスケープされて動作しません。改行文字はオプションですが、エスケープされていない改行文字を導入する方法もないようです。

簡単に言えば、このフォームはsudo -s <command>ワイルドカード、パイプ、スクリプトなどが関連していない場合にのみ機能するようです。しかし、通常、これらのコマンドを実行するためにシェルは実際には必要ありません!このような場合は、通常はsudo <command>使用せずに単に実行するだけで十分です。-s

sudoを実装する動機が何であるかはわかりません。おそらく追加または削除することもできます。たぶんlookahead-sによるものかもしれません。この場合、環境変数の設定方法に若干の違いがあります。-i-s


解決策:回避策はシェルを明示的に実行することです-c

これには$SHELL、ターゲットユーザーのコンテンツを理解することが含まれます(現在のユーザーと一致しない可能性があるため、$SHELL直接使用が常に正しいとは限りません)。

たとえば、代わりに次をsudo -s ls -l '/root/*.cfg'使用します。

$ sudo bash -c 'ls -l /root/*.cfg'

そして、sudo -i ls -l '~'以下を使用してください:

$ sudo bash -l -c 'ls -l ~'

(bashの引数は、-lで作成されたシェルと同じ「ログイン」シェルを生成しますsudo -i。)

関連情報