Bagaimana skrip saya dapat menentukan apakah skrip dijalankan oleh bash atau dash?

13

Saya menjalankan instalasi Oneiric baru (yaitu bukan upgrade) pada dua sistem yang berbeda dan menjalankan ke set yang sama masalah yang tampaknya terkait.

Yang paling membuat frustasi dari kumpulan itu adalah, ketika saya menggunakan .profile dan .bashrc yang saya bawa dari Mac OS X, masuk ke X melalui LightDM segera mengeluarkan saya. Saya percaya ini disebabkan oleh fakta bahwa, ketika menjalankan "/ bin / sh", ia berperilaku sebagai / bin / dash, tetapi masih memiliki variabel $ SHELL yang disetel ke / bin / bash.

Ekstrapolasi

Saya punya yang besar .bashrc. Anda dapat melihatnya di sini jika Anda mau, tetapi isinya mungkin tidak relevan, selain dari fakta bahwa itu penuh dengan bashisme, dan fakta bahwa ia berfungsi tanpa kesalahan di dalam xterm atau pada konsol virtual.

.profilePenampilan saya seperti ini (disingkat):

case $SHELL in 
*bash*)
    if [ -f $HOME/.bashrc -a -r $HOME/.bashrc ]; then
        . $HOME/.bashrc
    fi
    ;;
esac

Jika saya mencoba masuk ke X melalui LightDM, itu akan segera log saya kembali. Saya mendapatkan kesalahan .xsession-errorsterkait dengan .bashrc saya yang terlihat seperti ini (disingkat):

/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found

Seperti yang saya katakan, ketika saya menjalankan bash dari konsol virtual, saya tidak mendapatkan kesalahan ini. Selain itu, jika saya menghapus .profile saya, saya dapat masuk ke X dengan baik. (Saya juga dapat masuk ke konsol virtual dan menggunakan startxuntuk memulai sesi X yang berfungsi, tetapi ini tentu saja bukan solusi jangka panjang.)

Namun, saya menemukan bahwa jika saya menjalankan /bin/sh -l, saya tidak mendapatkan kesalahan. Berikut ini contoh sesi (catatan: bash prompt yang saya sederhanakan bash>, dan sh prompt adalah adil $):

bash> echo $SHELL
/bin/bash
bash> echo $BASH_VERSION
4.2.10(1)-release
bash> /bin/sh -l
/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found
$ echo $SHELL
/bin/bash
$ echo $BASH_VERSION

$

T1: Mengapa ini terjadi?

Saya mengerti bahwa / bin / sh sekarang menunjuk ke dash daripada bash , tetapi jika itu benar, lalu mengapa $SHELLmasih kembali /bin/bash?

T2: Apa yang bisa saya lakukan untuk mengatasinya?

Apakah ada cara untuk mengatasi ini? Saya ingin agar profil saya tetap memuat .bashrc sehingga saya mendapatkan lingkungan yang sama pada shell login dan non-login, tapi jelas saya hanya ingin memuatnya untuk bash sendiri, bukan / bin / sh yang menyamar sebagai bash.

Anda mungkin telah memperhatikan perbedaan isi dari variabel $ BASH_VERSION di atas. Saya telah mencoba membungkus. Profil saya dengan sesuatu seperti ini:

if [ -n $BASH_VERSION ]; then
    # the rest of my .profile as above
fi

The -nuji harus kembali benar hanya jika panjang string adalah non-nol, bagaimanapun, meskipun dalam sesi di atas, ketika saya berjalan di bawah /bin/sh -litu mengembalikan string kosong untuk $ BASH_VERSION, ketika itu termasuk dalam .profile saya seperti ini , ini lulus ujian! Itu mereka hasilkan ke .bashrc saya dan beri saya kesalahan yang sama seperti sebelumnya.

Sekarang saya benar - benar bingung.

Micah R Ledbetter
sumber
Catatan yang dash -ljuga menunjukkan $SHELLmemiliki nilai /bin/bash.
Scott Severance
3
$SHELLadalah apa pun bidang terakhir dalam /etc/passwd(atau getent passwd) kata.
Dijeda sampai pemberitahuan lebih lanjut.
@ DennisWilliamson Terima kasih , itulah yang perlu saya ketahui untuk menemukan jawaban yang tepat.
Micah R Ledbetter
Kamu melakukannya dengan salah. Anda harus memasukkan lingkungan non-bash-spesifik ke dalam ~/.profile, hal-hal khusus-bash di dalamnya ~/.bashrc, dan memiliki ~/.bash_profilesumber keduanya.
nyuszika7h

Jawaban:

12

Anda dapat membuat fakta yang $BASH_VERSIONkosong dashuntuk Anda:

if [ "$BASH_VERSION" = '' ]; then
    echo "This is dash."
else
    echo "This is bash."
fi
Scott Severance
sumber
2
Teknik "x" kuno dan hanya diperlukan dalam kulit kerang kuno . Gunakanif [ "$BASH_VERSION" = '' ]
Dijeda sampai pemberitahuan lebih lanjut.
@ DennisWilliamson: Terima kasih. Saya pikir teknik Anda khusus untuk Bash, tapi saya hanya mengistirahatkannya di Dash dan berhasil. Saya sudah mengedit jawaban saya.
Scott Severance
Atau gunakan-n saja , atau tidak sama sekali . (+1, meskipun. = ''Berfungsi dengan sangat baik.)
Eliah Kagan
5

Anda hanya perlu menggunakan tanda kutip pada variabel yang BASH_VERSIONakan digunakan-n

if [ -n "$BASH_VERSION" ];then
 echo "this is bash"; 
else 
 echo "this is dash";
fi
GM-Script-Writer-62850
sumber
1
karena [ "$EMPTY_STRING" ]bernilai false, Anda bahkan tidak memerlukannya -n. Anda hanya perlu mengutip variabel.
jeberle
2

Gunakan /proc/[PID]/cmdlineuntuk melihat apa skrip sedang dijalankan dan menguji apa yang ada di dalamnya. The $$variabel akan memberi kita PID dari shell berjalan. Jadi kita bisa membuat skrip seperti ini,

#!/bin/bash
if grep -q 'bash' /proc/$$/cmdline ;
then
    echo "This is bash"
else
    echo "This is some other shell"
fi

Berikut ini tes skrip yang sama:

$> bash test_script.sh                                                                                                
This is bash
$> dash test_script.sh                                                                                                
This is some other shell
Sergiy Kolodyazhnyy
sumber
Ini tidak akan berfungsi pada Mac. Periksa $ BASH_VERSION.
Austin Burk
2
@AustinBurk tidak perlu bekerja di Mac. Ini Tanya Ubuntu.
TheWanderer
@ Zacharee1 oh sial, aku tidak memperhatikan:,)
Austin Burk
Saya tidak ingin mengedit ini dari apa yang Anda inginkan, tetapi saya sarankan untuk menyebutkan batasan metode ini. Bash tidak perlu memiliki bashnamanya; itu tidak biasa untuk bashdieksekusi dijalankan melalui symlink dengan nama lain. Biasanya orang masih ingin mempertimbangkan Bash itu. Selain itu, polanya dicocokkan di mana saja di/proc/$$/cmdline , yang seharusnya memungkinkan untuk diperbaiki, tetapi perlu diingat bahwa argumen di cmdlineadalah karakter-nol dibatasi. grep -qE '(^|/)bash$'terasa seperti itu harus bekerja tetapi memberikan positif palsu ketika ada argumen bash.
Eliah Kagan
@EliahKagan Merasa bebas untuk mengedit jawaban saya kapan saja - Anda memiliki keahlian yang cukup sehingga saya tahu bahwa suntingan Anda hanya dapat menawarkan peningkatan. Jawabannya ditulis ketika saya jauh lebih hijau dengan cangkang daripada saya sekarang.
Sergiy Kolodyazhnyy