bash script: sudo ile veya sudo olmadan çağrıldığında farklı sonuçlar


10

Ubuntu 16.04.3'te çok basit bir bash betiğim var:

test.sh

[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0

Ben kök olmayan kullanıcı meveya olarak adlandırdığımda root, beklendiği gibi çalışır. Kullanırsam sudo ./test.sh, bir sözdizimi hatası hakkında şikayetçi:

$ ./test.sh
true
me /bin/bash ./test.sh

$ sudo su
# ./test.sh 
true
root /bin/bash ./test.sh

# exit
$ sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh

Buna ne sebep olabilir? meBu betiği hem normal hem de birlikte kullanabilmek için nasıl düzeltebilirim sudo?


3
Profesyonel ipucu: Koşmanın bir anlamı yoksudo su . Sadece koş sudo -iya da sudo -sonun yerine.
terdon

@terdon sudo -ikonumu olarak değiştirir /root. sudo suveya sudo -sdizin konumunu değiştirmeyin.
James Newton

Evet, neden için daha önce başvurduğum soruyu okuyun. Ve üzgünüm, önceki yorumumu düzenledim, bahsetmeyi unutmuştum -s.
terdon

Yanıtlar:


20

Her komut dosyası bir Shebang ile başlar, komut dosyası başlamadan önce kabuk, hangi yorumlayıcının komut dosyanızı 1 çalıştırması gerektiğini bilmez ve sudo ./script.shburada sholduğu gibi - Ubuntu 16.04'te bağlantılı olan çalıştırılabilir dash. Koşullu ifade [[ bir olan bashbileşik komut yüzden, dashidare ve karşılaşılan hata atıyor nasıl bilmiyor.

Buradaki çözüm,

#!/bin/bash

betiğinizin ilk satırı olarak. Açıkça ile aradığınızda aynı sonucu alabilirsiniz sudo bash ./script.sh, ancak bir shebang gitmek için bir yoldur.
Komut dosyanızı hangi kabuğun çalıştırdığını kontrol etmek için ekleyin echo $0. Wiki.archlinux.org'a atıfta bulunmakla aynı şey değildir :echo $SHELL

SHELL, kullanıcının tercih ettiği kabuğa giden yolu içerir. Bash başlangıçta bu değişkeni ayarlasa da, şu anda çalışan kabuk olmadığını mutlaka unutmayın.

1: başladıkça ./test.shile bashsadece farz bash, aynı gider sudo sualt kabuğa.


1
Ayrıca bash'ın bash kullanarak shebang olmadan bir komut dosyası çalıştırdığını unutmayın /bin/sh.
muru

@ tatlı Bu sorunu giderir. Teşekkürler! Hangi kabuğun çalıştığı bir komut dosyasından nasıl kontrol edebilirim ? ( echo $0Bana senaryonun adını verir: ./test.sh)
James Newton

@JamesNewton taşınabilir bir yol yok, AFAIK, ama neyi /proc/$$/exeişaret ettiğini kontrol edebilirsiniz . Ayrıca gibi çeşitli değişkenler test edebilirsiniz $BASH_VERSION, $ZSH_VERSIONvb (ama çizgi tür değişken set etmez)
Muru

5

Gibi @dessert açıkladı , buradaki sorun senaryonuzun sahip olmamasıdır mesele hattını . Bir shebang olmadan, sudovarsayılan kullanarak dosyayı çalıştırmak için çalışır /bin/sh. Ben hiçbir yerde belgelenmiş bulamadı, ama ben sudodosyada aşağıdakini buldum kaynak kodu kontrol ederek onayladı pathnames.h:

#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif /* _PATH_BSHELL */

Bu, "değişken _PATH_BSHELLtanımlanmadıysa ayarla, " olarak ayarla "anlamına gelir /bin/sh. Ardından, configurekaynak tarball'a dahil edilen senaryoda:

for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do
    if test -f "$p"; then
    found=yes
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5
$as_echo "$p" >&6; }
    cat >>confdefs.h <<EOF
#define _PATH_BSHELL "$p"
EOF

    break
    fi
done

Bu döngü arayacaktır /bin/bash, /usr/bin/sh, /sbin/sh, /usr/sbin/shveya /bin/kshdaha sonra ayarlar _PATH_BSHELLiçin ilk bulunmuştur hangisi . Yana /bin/shlistedeki ilk oldu ve eğer mümkünse _PATH_BSHELLolarak ayarlanır /bin/sh. Tüm bunların sonucu, sudoaksi belirtilmedikçe varsayılan kabuğunun olmasıdır /bin/sh.

Bu nedenle, sudovarsayılan olarak /bin/shve Ubuntu'da bu, bir dashPOSIX uyumlu kabuk için bir sembolik bağlantı olan şeyleri çalıştırmaya çalışır :

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 27  2015 /bin/sh -> dash

[[Yapı, POSIX standardına göre bir darbe özelliği tanımlanmamıştır ve ile anlaşılamamıştır dash:

$ bash -c '[[ true ]] && echo yes'
yes
$ dash -c '[[ true ]] && echo yes'
dash: 1: [[: not found

Ayrıntılı olarak, üç çağrıda denediniz:

  1. ./test.sh

    Hayır sudo; bir sapma çizgisinin yokluğunda, kabuğunuz dosyanın kendisini yürütmeye çalışır. Koştuğunuz için bash, bu etkili bir şekilde çalışır bash ./test.shve çalışır.

  2. sudo suardından ./test.sh.

    Burada, kullanıcı için yeni bir kabuk başlatıyorsunuz root. Bu, $SHELLo kullanıcı için ortam değişkeninde tanımlanmış olan kabuk olacaktır ve Ubuntu'da kökün varsayılan kabuğu bash:

    $ grep root /etc/passwd
    root:x:0:0:root:/root:/bin/bash
  3. sudo ./test.sh

    Burada, sudokomutu doğrudan yürütmenize izin veriyorsunuz . Varsayılan kabuk olduğundan /bin/shyukarıda açıklandığı bu komut dosyasını çalışmasını sağlar /bin/sholan dashve o zamandan beri başarısız dashanlamıyor [[.


Not : sudoVarsayılan kabuğun nasıl ayarlandığına dair ayrıntılar biraz daha karmaşık görünmektedir. Cevabımda belirtilen dosyaları değiştirmeyi denedim /bin/bashama sudohala varsayılan /bin/sh. Bu nedenle, kaynak kodda varsayılan kabuğun tanımlandığı başka yerler olmalıdır. Bununla birlikte, ana nokta ( sudovarsayılan olarak sh) hala duruyor.


Hiçbir yerde belgelenmiş bulamadım - ben de, sadece /bin/shhata mesajından kullanacağımı varsaydım - başka ne mümkün olabilir? Soru sudo'nun kullandığı kabuk · SO , ayrıca bakınız man sudo, COMMAND EXECUTION bölümü . Görünüşe göre sudoara kabuk kullanmıyor !
tatlı

1
@ tatlı Evet, execvevarsayılan sistem çağrısı kendi uygulamasını kullanır sh. Ve hayır, ara kabuklar ilgisizdir, bu komutu çalıştıran kabukla ilgili değil, verilen kabuk komut dosyasını okumak için kullanılan kabuk yorumlayıcıyla ilgilidir. Yani hayır, bir ara kabuk başlatmaz, ancak kabuk komut dosyaları için bir kabuk yorumlayıcısına ihtiyaç duyar.
terdon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.