Menguji kemampuan tertentu (misalnya apakah ia melakukan !substitusi?) Mungkin lebih portabel daripada menemukan nama shell. Kebiasaan setempat mungkin membuat Anda menjalankan sesuatu bernama /bin/shyang sebenarnya bisa berupa abu, tanda hubung, bash, dll.
msw
1
@ msw: Sepertinya komentar yang bagus kecuali itu membuat saya bertanya-tanya "bagaimana?".
nobar
Tampaknya tidak ada jawaban sederhana untuk pertanyaan ini. Jika kami tidak dapat menanyakan shell, mungkin pendekatan yang lebih baik adalah dengan selalu menentukan shell. Saya tidak yakin bahwa ini selalu mungkin, tetapi mungkin itu lebih mudah dicapai daripada yang umumnya orang pikirkan.
@Aniket, tidak banyak membantu karena Anda mungkin berpikir - itu hanya tertarik pada proses shell interaktif .
Toby Speight
Jawaban:
794
Ada tiga pendekatan untuk menemukan nama executable shell saat ini:
Harap dicatat bahwa ketiga pendekatan dapat dibodohi jika executable shell adalah /bin/sh, tetapi itu benar-benar diganti namanya bash, misalnya (yang sering terjadi).
Jadi pertanyaan kedua Anda apakah psoutput akan dilakukan dijawab dengan " tidak selalu ".
echo $0 - akan mencetak nama program ... yang dalam kasus shell adalah shell yang sebenarnya.
ps -ef | grep $$ | grep -v grep- ini akan mencari ID proses saat ini dalam daftar proses yang sedang berjalan. Karena proses saat ini adalah shell, itu akan dimasukkan.
Ini tidak 100% dapat diandalkan, karena Anda mungkin memiliki proses lain yang pscantumannya menyertakan nomor yang sama dengan ID proses shell, terutama jika ID itu adalah angka kecil (misalnya, jika PID shell adalah "5", Anda mungkin menemukan proses yang disebut "java5" atau "perl5" dalam grepoutput yang sama !). Ini adalah masalah kedua dengan pendekatan "ps", di atas tidak bisa mengandalkan nama shell.
echo $SHELL- Jalur ke shell saat ini disimpan sebagai SHELLvariabel untuk setiap shell. Peringatan untuk yang satu ini adalah bahwa jika Anda meluncurkan shell secara eksplisit sebagai subprocess (misalnya, itu bukan shell login Anda), Anda akan mendapatkan nilai shell login Anda sebagai gantinya. Jika itu suatu kemungkinan, gunakan pendekatan psatau $0.
Namun, jika executable tidak cocok dengan shell Anda yang sebenarnya (mis. /bin/shSebenarnya bash atau ksh), Anda memerlukan heuristik. Berikut adalah beberapa variabel lingkungan khusus untuk berbagai kerang:
$version diatur pada tcsh
$BASH diatur pada bash
$shell (huruf kecil) diatur ke nama shell aktual di csh atau tcsh
$ZSH_NAME diatur pada zsh
ksh memiliki $PS3dan $PS4mengatur, sedangkan shell Bourne normal ( sh) hanya memiliki $PS1dan $PS2mengatur. Ini umumnya tampaknya yang paling sulit untuk dibedakan - satu - satunya perbedaan dalam seluruh rangkaian variabel lingkungan antara shdan kshkami telah menginstal pada Solaris boxen adalah $ERRNO,$FCEDIT , $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, dan $TMOUT.
ps -p $$seperti yang ditunjukkan oleh Matthew Slattery . Untuk ksh: echo $KSH_VERSIONatau echo ${.sh.version}.
Dijeda sampai pemberitahuan lebih lanjut.
@Dennish - ksh saya sekarang tidak memiliki set KSH_VERSION. dan echo ${.sh.version}mengembalikan "Pergantian Buruk". Lihat solusi saya di atas
DVK
3
“ ps -ef | grep …... Ini bukan 100% diandalkan sebagai ...” Menggunakan ekspresi reguler sederhana melalui egrepatau grep -edengan mudah dapat membawa keandalan hingga untuk-semua-maksud-dan-tujuan 100%: ps -ef | egrep "^\s*\d+\s+$$\s+". The ^merek yakin kita mulai dari awal baris, yang \d+makan sampai UID, yang $$sesuai dengan PID, dan \s*dan \s+account untuk & memastikan spasi antara bagian-bagian lain.
Slipp D. Thompson
2
@ SlippD.Thompson tidak bekerja di GNU / Linux. Tapi ini sepertinya berhasil:ps -ef | awk '$2==pid' pid=$$
jarno
98
ps -p $$
harus bekerja di mana saja yang melibatkan ps -efdan grepdilakukan solusi (pada varian Unix apa pun yang mendukung opsi POSIXps ) dan tidak akan menderita dari false positive yang diperkenalkan dengan mengambil urutan angka yang mungkin muncul di tempat lain.
Beberapa shell memiliki versi bawaannya sendiri psyang mungkin tidak dimengerti -psehingga Anda mungkin perlu menggunakannya /bin/ps -p $$.
Dijeda sampai pemberitahuan lebih lanjut.
13
Semua kerang yang saya kenal mengerti $$kecuali fishyang harus Anda gunakan ps -p %self.
Dijeda sampai pemberitahuan lebih lanjut.
3
Sebenarnya, Anda tidak harus bergantung pada jalan yang sulit seperti /bin/ps. psbisa dengan mudah (sebenarnya itu cukup normal saat ini) dipasang di /usr/bin. $(which ps) -p $$adalah cara yang lebih baik. Tentu saja, ini tidak akan berhasil pada ikan, dan mungkin beberapa kerang lainnya. Saya pikir itu (which ps) -p %selfpada ikan.
Aron Cederholm
1
Dalam beberapa sistem minimal seperti wadah buruh pelabuhan debian-ramping, ps mungkin tidak ada. Dalam hal ini pendekatan ini masih berfungsi:readlink /proc/$$/exe
mxmlnkn
jika Anda shditiru oleh bash, ps -p memberi Anda /usr/bin/bashbahkan Anda menjalankannya sebagaish
Ini bagus pendek. Saya menggunakan diri saya sendiri ps -o fname --no-headers $$.
Anne van Rossum
Terima kasih. Saya menemukan ini opsi terbaik untuk digunakan dalam skrip untuk menjaga perintah spesifik bash test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash. (Baris berikutnya dalam skrip saya memiliki yang setara dengan csh.)
craq
1
Saya telah menemukan bahwa jika Anda melakukan ini dari dalam subkulit maka itu dapat menyebabkan garis tambahan palsu dengan mencocokkan PID induk serta proses shell yang sebenarnya. Untuk ini, saya menggunakan -qsebagai gantinya -p:SHELL=$(ps -ocomm= -q $$)
Steve
35
Jika Anda hanya ingin memastikan pengguna menggunakan skrip dengan Bash:
if[!-n "$BASH"];then echo Please run this script $0 with bash;exit1;fi
Ini harus menjadi yang lebih dekat ke atas. Terima kasih banyak.
Alex Skrypnyk
4
Seharusnya tidak lebih dekat ke atas, karena tidak menjawab pertanyaan sama sekali. Jika pertanyaannya adalah "Bagaimana cara memeriksa apakah skrip berjalan di bawah bash", saya memilihnya.
David Ferenczy Rogožan
2
@DawidFerenczy - Pertanyaan ini adalah hasil teratas ketika Anda mencari frasa itu. Dalam jangka panjang, saya pikir jauh lebih penting bahwa jawaban menjawab apa yang dicari orang daripada menjawab tentang pertanyaan aslinya.
ArtOfWarfare
3
Selain itu, $ BASH variabel yang didefinisikan dalam tcsh jika tcsh ini dipanggil dari bash
18446744073709551615
Ini sangat berguna, terima kasih. Hanya diadaptasi itu sedikit, menempatkan ini sebagai garis kedua setelah #!/bin/bash: if [ ! -n "$BASH" ] ;then exec bash $0; fi. Dengan baris ini skrip dijalankan menggunakan bash bahkan jika mulai menggunakan ksh atau sh. Kasus penggunaan saya tidak memerlukan argumen baris perintah, tetapi mereka dapat ditambahkan setelah $0jika perlu.
Apa gunanya grep diikuti awk, kapan ya /pattern/ { action }?
Jens
# in zshell alias shell = 'echo $ {SHELL: t}'
SergioAraujo
4
$SHELLvariabel lingkungan berisi shell, yang dikonfigurasi sebagai default untuk pengguna saat ini. Itu tidak mencerminkan shell, yang sedang berjalan. Juga lebih baik digunakan ps -p $$daripada menangkap $$ karena positif palsu.
David Ferenczy Rogožan
$ SHELL id. variabel menunjuk ke shell 'parent', sebagaimana ditentukan dalam spesifikasi POSIX: SHELL Variabel ini harus mewakili pathname dari penerjemah bahasa perintah yang disukai pengguna. Oleh karena itu nilai $ SHELL mungkin bukan shell saat ini.
Theo
semua dalam awk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
go2null
16
$SHELLtidak perlu selalu menampilkan shell saat ini. Ini hanya mencerminkan shell default yang akan dipanggil.
Untuk menguji di atas, katakanlah bashshell default, coba echo $SHELL, dan kemudian di terminal yang sama, masuk ke beberapa shell lain ( KornShell (ksh) misalnya) dan coba$SHELL . Anda akan melihat hasilnya sebagai bash dalam kedua kasus.
Untuk mendapatkan nama shell saat ini, Gunakan cat /proc/$$/cmdline. Dan path ke shell dieksekusi oleh readlink /proc/$$/exe.
ps adalah metode yang paling dapat diandalkan. Variabel lingkungan SHELL tidak dijamin akan ditetapkan dan bahkan jika itu, ia dapat dengan mudah dipalsukan.
+1 $ SHELL adalah shell default untuk program yang perlu memunculkan satu. Itu tidak mencerminkan shell yang sedang berjalan.
Jim Lewis
8
Saya punya trik sederhana untuk menemukan shell saat ini. Cukup ketikkan string acak (yang bukan perintah). Ini akan gagal dan mengembalikan kesalahan "tidak ditemukan", tetapi pada awal baris itu akan mengatakan shell mana itu:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Tidak bagus dalam naskah. echo 'aaaa' > script; chmod +x script; ./scriptmemberi./script.sh: 1: aaaa: not found
slim
6
Berikut ini akan selalu memberikan shell aktual yang digunakan - itu mendapatkan nama executable aktual dan bukan nama shell (yaitu ksh93bukannya ksh, dll.). Sebab /bin/sh, itu akan menunjukkan shell aktual yang digunakan, yaitu dash.
ls -l /proc/$$/exe | sed 's%.*/%%'
Saya tahu bahwa ada banyak yang mengatakan bahwa lsoutput tidak boleh diproses, tetapi berapa probabilitas Anda akan memiliki shell yang Anda gunakan yang diberi nama dengan karakter khusus atau ditempatkan di direktori bernama dengan karakter khusus? Jika ini masih terjadi, ada banyak contoh lain melakukannya secara berbeda.
Seperti yang ditunjukkan oleh Toby Speight , ini akan menjadi cara yang lebih tepat dan lebih bersih untuk mencapai hal yang sama:
Ini hanya kesalahan pada semua Unices yang tidak menyediakan /proc. Tidak semua kotak Linux di dunia.
Jens
5
Dan jika Anda berada di Linux, kami lebih memilih basename $(readlink /proc/$$/exe)untuk ls+ sed+ echo.
Toby Speight
1
Ini akan memberikan nama executable yang sebenarnya , bukan shell yang sebenarnya . Ketika shell aktual dihubungkan sebagai applet busybox, katakanlah ash -> /bin/busybox, ini akan memberikan / bin / busybox.
stepse
6
Saya telah mencoba berbagai pendekatan dan yang terbaik untuk saya adalah:
ps -p $$
Ini juga berfungsi di bawah Cygwin dan tidak dapat menghasilkan false positive sebagai PID grepping. Dengan sedikit pembersihan, hanya menghasilkan nama yang dapat dieksekusi (di bawah Cygwin dengan path):
ps -p $$ | tail -1| awk '{print $NF}'
Anda dapat membuat fungsi sehingga Anda tidak harus menghafalnya:
# Print currently active shell
shell (){
ps -p $$ | tail -1| awk '{print $NF}'}
Pada pengaturan saya (Cygwin | Windows 7) jawaban Anda adalah yang terbaik, dan ps -p $$ | ekor -1 | gawk '{print $ NF}' bekerja bahkan dari cmd tanpa $ bash. Harap perhatikan gawk alih-alih awk, karena awk hanya bekerja dari bash.
WebComer
@ WebComer Maaf, saya tidak yakin apa yang Anda maksud dengan " bekerja bahkan dari cmd tanpa $ bash ". Bahkan jika Anda akan memiliki port Windows ps, taildan gawk, cmd tidak mendefinisikan $$PID jadi itu pasti tidak dapat bekerja di bawah cmd polos.
David Ferenczy Rogožan
Kenapa tidak sederhana saja ps -p$$ -o comm=? POSIX mengatakan bahwa menentukan semua header kosong akan menekan header sepenuhnya. Kami masih gagal (seperti semua psjawaban) ketika kami bersumber dari skrip yang dieksekusi langsung (mis #!/bin/sh.).
Toby Speight
5
Varian saya saat mencetak proses induk:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Jangan menjalankan aplikasi yang tidak perlu ketika AWK dapat melakukannya untuk Anda.
Mengapa menjalankan yang tidak perlu awk, kapan ps -p "$$" -o 'comm='bisa melakukannya untuk Anda?
Toby Speight
5
Ada banyak cara untuk mengetahui shell dan versinya. Inilah beberapa yang bekerja untuk saya.
Mudah
$> echo $ 0 (Memberi Anda nama program. Dalam kasus saya, hasilnya adalah -bash .)
$> $ SHELL (Ini akan membawa Anda ke dalam shell dan pada prompt Anda mendapatkan nama dan versi shell. Dalam kasus saya, bash3.2 $ .)
$> echo $ SHELL (Ini akan memberi Anda jalur yang dapat dieksekusi. Dalam kasus saya / bin / bash .)
$> $ SHELL --version (Ini akan memberikan info lengkap tentang perangkat lunak shell dengan tipe lisensi)
Pendekatan hackish
$> ******* (Ketikkan satu set karakter acak dan dalam output Anda akan mendapatkan nama shell. Dalam kasus saya -bash: chapter2-a-sample-isomorphic-app: perintah tidak ditemukan )
Asalkan Anda /bin/shmendukung standar POSIX dan sistem Anda memiliki lsofperintah yang terinstal - kemungkinan alternatif lsofdalam hal ini adalah pid2path- Anda juga dapat menggunakan (atau mengadaptasi) skrip berikut yang mencetak path lengkap:
#!/bin/sh# cat /usr/local/bin/curshset-eu
pid="$$"set-- sh bash zsh ksh ash dash csh tcsh pdksh mksh fish psh rc scsh bournesh wish Wish login
unset echo env sed ps lsof awk getconf
# getconf _POSIX_VERSION # reliable test for availability of POSIX system?
PATH="`PATH=/usr/bin:/bin:/usr/sbin:/sbin getconf PATH`"[ $?-ne 0]&&{ echo "'getconf PATH' failed";exit1;}export PATH
cmd="lsof"
env -i PATH="${PATH}" type "$cmd"1>/dev/null2>&1||{ echo "$cmd not found";exit1;}
awkstr="`echo "$@" | sed 's/\([^ ]\{1,\}\)/|\/\1/g; s/ /$/g' | sed 's/^|//; s/$/$/'`"
ppid="`env -i PATH="${PATH}" ps -p $pid -o ppid=`"["${ppid}"X =""X ]&&{ echo "no ppid found";exit1;}
lsofstr="`lsof -p $ppid`"||{ printf "%s\n""lsof failed""try: sudo lsof -p \`ps -p \$\$ -o ppid=\`";exit1;}
printf "%s\n""${lsofstr}"|
LC_ALL=C awk -v var="${awkstr}"'$NF ~ var {print $NF}'
ini bekerja pada ikan! tetapi bagi saya, gagal di bash, karena opsi -i(-> abaikan lingkungan) envdi baris tempat Anda memeriksa lsofketersediaan. gagal dengan: env -i PATH="${PATH}" type lsof->env: ‘type’: No such file or directory
hoijui
2
Jika Anda hanya ingin memastikan bahwa Anda menjalankan (versi tertentu) Bash, cara terbaik untuk melakukannya adalah dengan menggunakan $BASH_VERSINFO variabel array. Sebagai variabel array (baca-saja), variabel ini tidak dapat diatur di lingkungan, jadi Anda dapat yakin itu datang (jika sama sekali) dari shell saat ini.
Namun, karena Bash memiliki perilaku yang berbeda ketika dipanggil sh, Anda juga perlu memeriksa $BASHvariabel lingkungan yang diakhiri /bash.
Dalam skrip yang saya tulis yang menggunakan nama fungsi dengan -(bukan garis bawah), dan tergantung pada array asosiatif (ditambahkan dalam Bash 4), saya memiliki pemeriksaan kewarasan berikut (dengan pesan kesalahan pengguna yang membantu):
case`eval 'echo $BASH@${BASH_VERSINFO[0]}' 2>/dev/null`in*/bash@[456789])# Claims bash version 4+, check for func-names and associative arraysif!eval"declare -A _ARRAY && func-name() { :; }"2>/dev/null;then
echo >&2"bash $BASH_VERSION is not supported (not really bash?)"exit1fi;;*/bash@[123])
echo >&2"bash $BASH_VERSION is not supported (version 4+ required)"exit1;;*)
echo >&2"This script requires BASH (version 4+) - not regular sh"
echo >&2"Re-run as \"bash $CMD\" for proper operation"exit1;;esac
Anda bisa menghilangkan pemeriksaan fungsional yang agak paranoid untuk fitur dalam kasus pertama, dan hanya berasumsi bahwa versi Bash masa depan akan kompatibel.
Tidak ada jawaban yang bekerja dengan fishshell (tidak memiliki variabel $$atau $0).
Ini bekerja untuk saya (diuji pada sh, bash, fish, ksh, csh, true, tcsh, dan zsh; openSUSE 13.2):
ps | tail -n 4| sed -E '2,$d;s/.* (.*)/\1/'
Perintah ini menghasilkan string seperti bash. Di sini saya hanya menggunakan ps,, taildan sed(tanpa ekstensi GNU; coba tambahkan --posixuntuk memeriksanya). Itu semua adalah perintah POSIX standar. Saya yakin tailbisa dihapus, tetapi sedfu saya tidak cukup kuat untuk melakukan ini.
Menurut saya, solusi ini tidak terlalu portabel karena tidak berfungsi pada OS X. :(
Ini harus portabel di berbagai platform dan cangkang. Ini menggunakan psseperti solusi lain, tetapi tidak bergantung pada seddan awkdan menyaring sampah dari perpipaan dan psitu sendiri sehingga shell harus selalu menjadi entri terakhir. Dengan cara ini kita tidak perlu bergantung pada variabel PID non-portabel atau memilih garis dan kolom yang tepat.
Saya telah menguji Debian dan macOS dengan Bash, Z shell ( zsh), dan ikan (yang tidak bekerja dengan sebagian besar solusi ini tanpa mengubah ekspresi khusus untuk ikan, karena menggunakan variabel PID yang berbeda).
Mencoba ini saat menggunakan zsh, dan itu memberi saya -bash.
user137369
Pada sistem saya (sekarang), diuji dengan bash dan dash, ini kembali mutt...: -b
F. Hauri
1
Grepping PID dari output "ps" tidak diperlukan, karena Anda dapat membaca baris perintah masing-masing untuk setiap PID dari struktur direktori / proc:
echo $(cat /proc/$$/cmdline)
Namun, itu mungkin tidak lebih baik dari sekadar:
echo $0
Tentang menjalankan shell yang sebenarnya berbeda dari yang ditunjukkan namanya, satu ide adalah meminta versi dari shell menggunakan nama yang Anda dapatkan sebelumnya:
<some_shell> --version
sh tampaknya gagal dengan kode keluar 2 sementara yang lain memberikan sesuatu yang bermanfaat (tetapi saya tidak dapat memverifikasi semuanya karena saya tidak memilikinya):
Ini bukan solusi yang sangat bersih, tetapi melakukan apa yang Anda inginkan.
# MUST BE SOURCED..
getshell(){local shell="`ps -p $$ | tail -1 | awk '{print $4}'`"
shells_array=(# It is important that the shells are listed in descending order of their name length.
pdksh
bash dash mksh
zsh ksh
sh
)local suited=falsefor i in ${shells_array[*]};doif![-z `printf $shell | grep $i`]&&! $suited;then
shell=$i
suited=truefidone
echo $shell
}
getshell
Sekarang kamu bisa menggunakannya $(getshell) --version.
Ini bekerja, meskipun, hanya pada kerang mirip KornShell (ksh).
"Tapi ini hanya bisa digunakan pada kerang mirip ksh." Apakah Anda mengatakan saya harus memverifikasi shell sebelum menjalankan ini? Hmm ...
jpaugh
@jpaugh, daftar harus didukung oleh shell sumber kode ini, yang tidak kasus untuk dash, yashdll Biasanya, jika Anda menggunakan bash, zsh, ksh, apa pun - Anda harus tidak peduli tentang hal-hal seperti itu.
theoden8
Jadi Anda menghitung bash sebagai "ksh-like"? Oke. Itu lebih masuk akal
jpaugh
@ jpaugh, well, itulah yang saya maksudkan karena kshset fitur sebagian besar merupakan subset dari bashfitur (belum memeriksa ini dengan seksama sekalipun).
theoden8
1
Lakukan hal berikut untuk mengetahui apakah shell Anda menggunakan Dash / Bash.
ls –la /bin/sh:
jika hasilnya /bin/sh -> /bin/bash==> Kemudian shell Anda menggunakan Bash.
jika hasilnya /bin/sh ->/bin/dash==> Kemudian shell Anda menggunakan Dash.
Jika Anda ingin mengubah dari Bash ke Dash atau sebaliknya, gunakan kode di bawah ini:
ln -s /bin/bash /bin/sh (ganti shell ke Bash)
Catatan : Jika perintah di atas menghasilkan kesalahan yang mengatakan, / bin / sh sudah ada, hapus / bin / sh dan coba lagi.
Yang pertama adalah omong kosong, echo $SHELLlakukan apa yang Anda coba lakukan dan lakukan dengan baik. Yang kedua juga tidak baik, karena $SHELLvariabel lingkungan berisi shell default untuk pengguna saat ini, bukan shell yang sedang berjalan. Jika saya misalnya telah bashditetapkan sebagai shell default, jalankan zshdan echo $SHELL, itu akan dicetak bash.
David Ferenczy Rogožan
Anda benar Dawid Ferenczy, Kita bisa menggunakan perintah ps untuk menentukan shell saat ini. [# ps -p $$ | ekor -1 | awk '{print $ 4}'].
!
substitusi?) Mungkin lebih portabel daripada menemukan nama shell. Kebiasaan setempat mungkin membuat Anda menjalankan sesuatu bernama/bin/sh
yang sebenarnya bisa berupa abu, tanda hubung, bash, dll.Jawaban:
Ada tiga pendekatan untuk menemukan nama executable shell saat ini:
Harap dicatat bahwa ketiga pendekatan dapat dibodohi jika executable shell adalah
/bin/sh
, tetapi itu benar-benar diganti namanyabash
, misalnya (yang sering terjadi).Jadi pertanyaan kedua Anda apakah
ps
output akan dilakukan dijawab dengan " tidak selalu ".echo $0
- akan mencetak nama program ... yang dalam kasus shell adalah shell yang sebenarnya.ps -ef | grep $$ | grep -v grep
- ini akan mencari ID proses saat ini dalam daftar proses yang sedang berjalan. Karena proses saat ini adalah shell, itu akan dimasukkan.Ini tidak 100% dapat diandalkan, karena Anda mungkin memiliki proses lain yang
ps
cantumannya menyertakan nomor yang sama dengan ID proses shell, terutama jika ID itu adalah angka kecil (misalnya, jika PID shell adalah "5", Anda mungkin menemukan proses yang disebut "java5" atau "perl5" dalamgrep
output yang sama !). Ini adalah masalah kedua dengan pendekatan "ps", di atas tidak bisa mengandalkan nama shell.echo $SHELL
- Jalur ke shell saat ini disimpan sebagaiSHELL
variabel untuk setiap shell. Peringatan untuk yang satu ini adalah bahwa jika Anda meluncurkan shell secara eksplisit sebagai subprocess (misalnya, itu bukan shell login Anda), Anda akan mendapatkan nilai shell login Anda sebagai gantinya. Jika itu suatu kemungkinan, gunakan pendekatanps
atau$0
.Namun, jika executable tidak cocok dengan shell Anda yang sebenarnya (mis.
/bin/sh
Sebenarnya bash atau ksh), Anda memerlukan heuristik. Berikut adalah beberapa variabel lingkungan khusus untuk berbagai kerang:$version
diatur pada tcsh$BASH
diatur pada bash$shell
(huruf kecil) diatur ke nama shell aktual di csh atau tcsh$ZSH_NAME
diatur pada zshksh memiliki
$PS3
dan$PS4
mengatur, sedangkan shell Bourne normal (sh
) hanya memiliki$PS1
dan$PS2
mengatur. Ini umumnya tampaknya yang paling sulit untuk dibedakan - satu - satunya perbedaan dalam seluruh rangkaian variabel lingkungan antarash
danksh
kami telah menginstal pada Solaris boxen adalah$ERRNO
,$FCEDIT
,$LINENO
,$PPID
,$PS3
,$PS4
,$RANDOM
,$SECONDS
, dan$TMOUT
.sumber
ps -p $$
seperti yang ditunjukkan oleh Matthew Slattery . Untukksh
:echo $KSH_VERSION
atauecho ${.sh.version}
.echo ${.sh.version}
mengembalikan "Pergantian Buruk". Lihat solusi saya di atasps -ef | grep …
... Ini bukan 100% diandalkan sebagai ...” Menggunakan ekspresi reguler sederhana melaluiegrep
ataugrep -e
dengan mudah dapat membawa keandalan hingga untuk-semua-maksud-dan-tujuan 100%:ps -ef | egrep "^\s*\d+\s+$$\s+"
. The^
merek yakin kita mulai dari awal baris, yang\d+
makan sampai UID, yang$$
sesuai dengan PID, dan\s*
dan\s+
account untuk & memastikan spasi antara bagian-bagian lain.ps -ef | awk '$2==pid' pid=$$
ps -p $$
harus bekerja di mana saja yang melibatkan
ps -ef
dangrep
dilakukan solusi (pada varian Unix apa pun yang mendukung opsi POSIXps
) dan tidak akan menderita dari false positive yang diperkenalkan dengan mengambil urutan angka yang mungkin muncul di tempat lain.sumber
ps
yang mungkin tidak dimengerti-p
sehingga Anda mungkin perlu menggunakannya/bin/ps -p $$
.$$
kecualifish
yang harus Anda gunakanps -p %self
./bin/ps
.ps
bisa dengan mudah (sebenarnya itu cukup normal saat ini) dipasang di/usr/bin
.$(which ps) -p $$
adalah cara yang lebih baik. Tentu saja, ini tidak akan berhasil pada ikan, dan mungkin beberapa kerang lainnya. Saya pikir itu(which ps) -p %self
pada ikan.readlink /proc/$$/exe
sh
ditiru olehbash
, ps -p memberi Anda/usr/bin/bash
bahkan Anda menjalankannya sebagaish
Mencoba
atau
sumber
ps -o fname --no-headers $$
.test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash
. (Baris berikutnya dalam skrip saya memiliki yang setara dengan csh.)-q
sebagai gantinya-p
:SHELL=$(ps -ocomm= -q $$)
Jika Anda hanya ingin memastikan pengguna menggunakan skrip dengan Bash:
sumber
#!/bin/bash
:if [ ! -n "$BASH" ] ;then exec bash $0; fi
. Dengan baris ini skrip dijalankan menggunakan bash bahkan jika mulai menggunakan ksh atau sh. Kasus penggunaan saya tidak memerlukan argumen baris perintah, tetapi mereka dapat ditambahkan setelah$0
jika perlu.Anda dapat mencoba:
Atau:
sumber
/pattern/ { action }
?$SHELL
variabel lingkungan berisi shell, yang dikonfigurasi sebagai default untuk pengguna saat ini. Itu tidak mencerminkan shell, yang sedang berjalan. Juga lebih baik digunakanps -p $$
daripada menangkap $$ karena positif palsu.awk
,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$SHELL
tidak perlu selalu menampilkan shell saat ini. Ini hanya mencerminkan shell default yang akan dipanggil.Untuk menguji di atas, katakanlah
bash
shell default, cobaecho $SHELL
, dan kemudian di terminal yang sama, masuk ke beberapa shell lain ( KornShell (ksh) misalnya) dan coba$SHELL
. Anda akan melihat hasilnya sebagai bash dalam kedua kasus.Untuk mendapatkan nama shell saat ini, Gunakan
cat /proc/$$/cmdline
. Dan path ke shell dieksekusi olehreadlink /proc/$$/exe
.sumber
/proc
.ps adalah metode yang paling dapat diandalkan. Variabel lingkungan SHELL tidak dijamin akan ditetapkan dan bahkan jika itu, ia dapat dengan mudah dipalsukan.
sumber
Saya punya trik sederhana untuk menemukan shell saat ini. Cukup ketikkan string acak (yang bukan perintah). Ini akan gagal dan mengembalikan kesalahan "tidak ditemukan", tetapi pada awal baris itu akan mengatakan shell mana itu:
sumber
echo 'aaaa' > script; chmod +x script; ./script
memberi./script.sh: 1: aaaa: not found
Berikut ini akan selalu memberikan shell aktual yang digunakan - itu mendapatkan nama executable aktual dan bukan nama shell (yaitu
ksh93
bukannyaksh
, dll.). Sebab/bin/sh
, itu akan menunjukkan shell aktual yang digunakan, yaitudash
.Saya tahu bahwa ada banyak yang mengatakan bahwa
ls
output tidak boleh diproses, tetapi berapa probabilitas Anda akan memiliki shell yang Anda gunakan yang diberi nama dengan karakter khusus atau ditempatkan di direktori bernama dengan karakter khusus? Jika ini masih terjadi, ada banyak contoh lain melakukannya secara berbeda.Seperti yang ditunjukkan oleh Toby Speight , ini akan menjadi cara yang lebih tepat dan lebih bersih untuk mencapai hal yang sama:
sumber
/proc
. Tidak semua kotak Linux di dunia.basename $(readlink /proc/$$/exe)
untukls
+sed
+echo
.ash -> /bin/busybox
, ini akan memberikan / bin / busybox.Saya telah mencoba berbagai pendekatan dan yang terbaik untuk saya adalah:
Ini juga berfungsi di bawah Cygwin dan tidak dapat menghasilkan false positive sebagai PID grepping. Dengan sedikit pembersihan, hanya menghasilkan nama yang dapat dieksekusi (di bawah Cygwin dengan path):
Anda dapat membuat fungsi sehingga Anda tidak harus menghafalnya:
... dan kemudian jalankan
shell
.Itu diuji di bawah Debian dan Cygwin.
sumber
ps
,tail
dangawk
, cmd tidak mendefinisikan$$
PID jadi itu pasti tidak dapat bekerja di bawah cmd polos.ps -p$$ -o comm=
? POSIX mengatakan bahwa menentukan semua header kosong akan menekan header sepenuhnya. Kami masih gagal (seperti semuaps
jawaban) ketika kami bersumber dari skrip yang dieksekusi langsung (mis#!/bin/sh
.).Varian saya saat mencetak proses induk:
Jangan menjalankan aplikasi yang tidak perlu ketika AWK dapat melakukannya untuk Anda.
sumber
awk
, kapanps -p "$$" -o 'comm='
bisa melakukannya untuk Anda?Ada banyak cara untuk mengetahui shell dan versinya. Inilah beberapa yang bekerja untuk saya.
Mudah
Pendekatan hackish
$> ******* (Ketikkan satu set karakter acak dan dalam output Anda akan mendapatkan nama shell. Dalam kasus saya -bash: chapter2-a-sample-isomorphic-app: perintah tidak ditemukan )
sumber
Asalkan Anda
/bin/sh
mendukung standar POSIX dan sistem Anda memilikilsof
perintah yang terinstal - kemungkinan alternatiflsof
dalam hal ini adalahpid2path
- Anda juga dapat menggunakan (atau mengadaptasi) skrip berikut yang mencetak path lengkap:sumber
-i
(-> abaikan lingkungan)env
di baris tempat Anda memeriksalsof
ketersediaan. gagal dengan:env -i PATH="${PATH}" type lsof
->env: ‘type’: No such file or directory
Jika Anda hanya ingin memastikan bahwa Anda menjalankan (versi tertentu) Bash, cara terbaik untuk melakukannya adalah dengan menggunakan
$BASH_VERSINFO
variabel array. Sebagai variabel array (baca-saja), variabel ini tidak dapat diatur di lingkungan, jadi Anda dapat yakin itu datang (jika sama sekali) dari shell saat ini.Namun, karena Bash memiliki perilaku yang berbeda ketika dipanggil
sh
, Anda juga perlu memeriksa$BASH
variabel lingkungan yang diakhiri/bash
.Dalam skrip yang saya tulis yang menggunakan nama fungsi dengan
-
(bukan garis bawah), dan tergantung pada array asosiatif (ditambahkan dalam Bash 4), saya memiliki pemeriksaan kewarasan berikut (dengan pesan kesalahan pengguna yang membantu):Anda bisa menghilangkan pemeriksaan fungsional yang agak paranoid untuk fitur dalam kasus pertama, dan hanya berasumsi bahwa versi Bash masa depan akan kompatibel.
sumber
Tidak ada jawaban yang bekerja dengan
fish
shell (tidak memiliki variabel$$
atau$0
).Ini bekerja untuk saya (diuji pada
sh
,bash
,fish
,ksh
,csh
,true
,tcsh
, danzsh
; openSUSE 13.2):Perintah ini menghasilkan string seperti
bash
. Di sini saya hanya menggunakanps
,,tail
dansed
(tanpa ekstensi GNU; coba tambahkan--posix
untuk memeriksanya). Itu semua adalah perintah POSIX standar. Saya yakintail
bisa dihapus, tetapised
fu saya tidak cukup kuat untuk melakukan ini.Menurut saya, solusi ini tidak terlalu portabel karena tidak berfungsi pada OS X. :(
sumber
sed: invalid option -- 'E'
bash 3.2.51 dan tcsh 6.15.00Solusi saya:
Ini harus portabel di berbagai platform dan cangkang. Ini menggunakan
ps
seperti solusi lain, tetapi tidak bergantung padased
danawk
dan menyaring sampah dari perpipaan danps
itu sendiri sehingga shell harus selalu menjadi entri terakhir. Dengan cara ini kita tidak perlu bergantung pada variabel PID non-portabel atau memilih garis dan kolom yang tepat.Saya telah menguji Debian dan macOS dengan Bash, Z shell (
zsh
), dan ikan (yang tidak bekerja dengan sebagian besar solusi ini tanpa mengubah ekspresi khusus untuk ikan, karena menggunakan variabel PID yang berbeda).sumber
Dari Bagaimana Anda tahu apa shell Anda saat ini? .
sumber
grep $$
tidak bisa diandalkan.ps -ef | awk -v pid=$$ '$2==pid { print $8 }'
lebih baik, tapi kenapa tidak pakai sajaps -p $$
?Di Mac OS X (dan FreeBSD):
sumber
zsh
, dan itu memberi saya-bash
.mutt
...: -bGrepping PID dari output "ps" tidak diperlukan, karena Anda dapat membaca baris perintah masing-masing untuk setiap PID dari struktur direktori / proc:
Namun, itu mungkin tidak lebih baik dari sekadar:
Tentang menjalankan shell yang sebenarnya berbeda dari yang ditunjukkan namanya, satu ide adalah meminta versi dari shell menggunakan nama yang Anda dapatkan sebelumnya:
sh
tampaknya gagal dengan kode keluar 2 sementara yang lain memberikan sesuatu yang bermanfaat (tetapi saya tidak dapat memverifikasi semuanya karena saya tidak memilikinya):sumber
Ini bukan solusi yang sangat bersih, tetapi melakukan apa yang Anda inginkan.
Sekarang kamu bisa menggunakannya
$(getshell) --version
.Ini bekerja, meskipun, hanya pada kerang mirip KornShell (ksh).
sumber
dash
,yash
dll Biasanya, jika Anda menggunakanbash
,zsh
,ksh
, apa pun - Anda harus tidak peduli tentang hal-hal seperti itu.ksh
set fitur sebagian besar merupakan subset daribash
fitur (belum memeriksa ini dengan seksama sekalipun).Lakukan hal berikut untuk mengetahui apakah shell Anda menggunakan Dash / Bash.
ls –la /bin/sh
:jika hasilnya
/bin/sh -> /bin/bash
==> Kemudian shell Anda menggunakan Bash.jika hasilnya
/bin/sh ->/bin/dash
==> Kemudian shell Anda menggunakan Dash.Jika Anda ingin mengubah dari Bash ke Dash atau sebaliknya, gunakan kode di bawah ini:
ln -s /bin/bash /bin/sh
(ganti shell ke Bash)Catatan : Jika perintah di atas menghasilkan kesalahan yang mengatakan, / bin / sh sudah ada, hapus / bin / sh dan coba lagi.
sumber
Dan saya datang dengan ini
sumber
Silakan gunakan perintah di bawah ini:
sumber
echo $SHELL
lakukan apa yang Anda coba lakukan dan lakukan dengan baik. Yang kedua juga tidak baik, karena$SHELL
variabel lingkungan berisi shell default untuk pengguna saat ini, bukan shell yang sedang berjalan. Jika saya misalnya telahbash
ditetapkan sebagai shell default, jalankanzsh
danecho $SHELL
, itu akan dicetakbash
.echo $SHELL
mungkin sampah:~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
Yang ini berfungsi dengan baik di Red Hat Linux (RHEL), macOS, BSD dan beberapa AIXes :
Atau, yang berikut ini juga harus berfungsi jika pstree tersedia,
sumber