web-dev-qa-db-ja.com

シェルスクリプト内で「Sudo su」を使用できないのはなぜですか?シェルスクリプトをSudoで自動的に実行する方法

これの何が悪いのか分かりません。端末で実行してパスワードを入力しても何も起こりませんが、端末ですべてのコマンドを個別に実行すると機能します。ありがとうございました!

#!/bin/bash    

Sudo su;
mkdir /opt/D3GO/;
cp `pwd`/D3GO /opt/D3GO/;
cp `pwd`/D3GO.png /opt/D3GO/;
cp `pwd`/D3GO.desktop /usr/share/applications/;
chmod +x /opt/D3GO/D3GO
12
Dusan Milosevic

コマンドSudo suは対話型のルートシェルを起動しますが、現在のシェルをルートシェルに変換しません。

あなたが望むことをするためのイディオムはこれに沿ったものです(特に注意を払って@CharlesDuffyに感謝します):

#check for root
UID=$(id -u)
if [ x$UID != x0 ] 
then
    #Beware of how you compose the command
    printf -v cmd_str '%q ' "$0" "$@"
    exec Sudo su -c "$cmd_str"
fi

#I am root
mkdir /opt/D3GO/
#and the rest of your commands

アイデアは、現在のユーザーがrootであるかどうかを確認し、そうでない場合は、suを使用して同じコマンドを再実行することです

15
rodrigo

Here Documents を使用して、対話型シェルスクリプトに入力をリダイレクトできます。オペレーター <<は、指定された区切り文字を含む行がEOF(ファイルの終わり)として見つかるまで入力を読み取る命令です。

Sudo su <<EOF
echo "code"
EOF

例えば.

#!/bin/bash    
Sudo su <<EOF
mkdir /opt/D3GO/
cp `pwd`/D3GO /opt/D3GO/
cp `pwd`/D3GO.png /opt/D3GO/
cp `pwd`/D3GO.desktop /usr/share/applications/
chmod +x /opt/D3GO/D3GO
EOF
14
acfreitas

Sudo suはシェル内で実行されるコマンドではありません新しいシェルを開始します

新しいシェルはスクリプトを実行しなくなり、スクリプトを実行している古いシェルisは、新しいシェルが終了するのを待ってから続行します。

8
Charles Duffy

受け入れられた答え はうまく機能しますが、[オンデマンドでSudoを使用して自身を再起動するスクリプトのイディオムsimplifiedおよび作成済みよりポータブル

[[ $(id -u) -eq 0 ]] || exec Sudo /bin/bash -c "$(printf '%q ' "$BASH_SOURCE" "$@")"
  • [[ ... ]]の代わりに[ ... ]を使用すると、オペランドの前にxを追加する(またはLHSを二重引用符で囲む)必要がなくなります。

  • bash -cの代わりにsu -cを使用して、再構築されたコマンドラインを解釈すると、すべてのプラットフォームがsu -cをサポートするわけではないため(たとえば、macOSはサポートしないため)、コマンドの移植性が高まります。

  • bashでは、通常、$BASH_SOURCEが実行中のスクリプトを参照するためのより信頼できる方法です。


上記のアプローチでは、引数内の変数参照またはコマンド/算術置換は、常に呼び出しシェルによって展開されます。

代わりにdelay expanded--root user-のコンテキストでSudoシェルが実行されるまで変数参照が展開されないようにする場合これを使って:

(( __reinvoked )) || exec Sudo -s __reinvoked=1 "$BASH_SOURCE" "$@"

変数参照またはコマンド置換を含む引数を遅延拡張するためには、単一-引用符で囲む必要があることに注意してください。例:'$USER'

アドホック環境変数__reinvokedを使用して、正確に1回だけ再呼び出しできるように注意してください(最初にすでにrootユーザーとして呼び出されている場合でも)。


最初のテクニックを示すサンプルスクリプトは次のとおりです。

  • Rootとして呼び出されない場合、スクリプトはSudo -sで自分自身を再度呼び出し、すべての引数をそのまま渡します。

  • 以前に認証されていなくても、タイムアウト期間内であれば、Sudoは管理者パスワードの入力を求めます。

#!/bin/bash

[[ $(id -u) -eq 0 ]] || exec Sudo /bin/bash -c "$(printf '%q ' "$BASH_SOURCE" "$@")"

# Print the username and all arguments.
echo "Running as: $(id -un)"
echo "Arguments:"
for arg; do echo "  $((++i)): [$arg]"; done

acfreitasの役立つ回答"script-inside-a-script"テクニックのデモンストレーションhere-documentは、stdinを介してシェルコードを提供するために使用されますSudo su
繰り返しになりますが、Sudo -sで十分ですおよび引用が重要

Sudo -s -H <<'EOF'
echo "$HOME"
EOF

文書の内容が先行現在で解釈されないようにするために、ここで開始するヒアドキュメントの区切り文字(この場合はEOF)がどのように引用符で囲まれていることに注意してください。シェル。
EOF(の一部)を引用しなかった場合、$HOMEcurrentユーザーのホームディレクトリに展開されます。

ミックス先行展開と遅延展開にする場合は、ここの開始ドキュメントの区切り文字引用符なしを残し、選択的に\- quote $インスタンスを残します:

Sudo -s -H <<EOF
echo "Called by: $USER; root's home dir: \$HOME"
EOF
8
mklement0

Sudo suはrootとして新しいシェルを起動しようとします。新しいシェルを開くと、新しいシェルを閉じるまで元のスクリプトは続行されません。

修正してみるには:

シェルスクリプトで次を試してください。

su <username> -c "my command"

したがって、ユーザーが「userA」の場合:

su userA -c "mkdir /opt/D3GO/"

ただし、たとえばuserAで、スクリプトの一部をrootとして実行する場合は、パスの入力を求められます。

su root -c "mkdir /opt/D3GO/"

そもそもSudoを使用してスクリプトを実行するだけでも回避できます。

Sudo ./myScript.sh

このようにして、スクリプトはスクリプト内の元のユーザーを保持します。これには、$ {USERNAME}などの標準変数を使用してアクセスできます。 $ {UID}など

何があなたのためにうまくいくかに依存します。

2
Amos

「Sudo su」を実行すると新しいシェルが開き、そのシェルを終了するまでコマンドは返されないためです。おそらく、スクリプトを2つのファイルに分割します。最初のファイルはSudoを実行し、その2番目のスクリプトをSudoの下で実行します。

2
MK.