Üzerinde çalıştığım kabuğu nasıl belirleyebilirim?
ps
Komutun çıktısı tek başına yeterli olur mu?
Bu, Unix'in farklı tatlarında nasıl yapılabilir?
Üzerinde çalıştığım kabuğu nasıl belirleyebilirim?
ps
Komutun çıktısı tek başına yeterli olur mu?
Bu, Unix'in farklı tatlarında nasıl yapılabilir?
Yanıtlar:
Geçerli kabuğun yürütülebilir dosyasının adını bulmak için üç yaklaşım vardır :
Kabuğun çalıştırılabilir olması durumunda her üç yaklaşımın da kandırılabileceğini lütfen unutmayın /bin/sh
, ancak bu gerçekten yeniden adlandırılmıştır bash
, örneğin (sıklıkla gerçekleşir).
Böylece ps
çıktının yapılıp yapılmayacağına dair ikinci sorunuz " her zaman değil " şeklinde yanıtlanır .
echo $0
- program adını yazdıracaktır ... kabuk durumunda gerçek kabuktur.
ps -ef | grep $$ | grep -v grep
- bu işlem, çalışan işlemler listesinde geçerli işlem kimliğini arayacaktır. Mevcut süreç kabuk olduğu için dahil edilecektir.
Bu% 100 güvenilir değildir , listelemesi kabuk işlem kimliğiyle aynı sayıyı içeren başka işlemleriniz olabileceğinden ps
, özellikle bu kimlik küçük bir sayıysa (örneğin, kabuğun PID'si "5" ise, şu işlemleri bulabilirsiniz: "java5" veya "perl5" aynı grep
çıktıda!). Bu "ps" yaklaşımıyla ilgili ikinci problemdir, üstelik kabuk adına güvenememek.
echo $SHELL
- Geçerli kabuğa giden yol, SHELL
herhangi bir kabuğun değişkeni olarak saklanır . Bunun bir uyarısı, bir kabuğu bir alt işlem olarak açıkça başlatırsanız (örneğin, giriş kabuğunuz değil), bunun yerine giriş kabuğunuzun değerini alırsınız. Bu bir olasılıksa, ps
veya $0
yaklaşımını kullanın .
Ancak, yürütülebilir dosya gerçek kabuğunuzla eşleşmiyorsa (örn /bin/sh
. Aslında bash veya ksh ise) sezgisel tarama gerekir. Çeşitli kabuklara özgü bazı çevresel değişkenler şunlardır:
$version
tcsh'de ayarlandı
$BASH
bash üzerine ayarlandı
$shell
(küçük harf) csh veya tcsh cinsinden gerçek kabuk adına ayarlanır
$ZSH_NAME
zsh olarak ayarlandı
ksh vardır $PS3
ve $PS4
ayarlanır, oysa normal Bourne kabuğu ( sh
) sadece vardır $PS1
ve $PS2
ayarlanır. Bu genellikle gibi görünüyor zor ayırt etmek - sadece arasındaki ortam değişkenleri tüm kümeye farkı sh
ve ksh
biz Solaris boxen yüklemiş olduğu $ERRNO
, $FCEDIT
, $LINENO
, $PPID
, $PS3
, $PS4
, $RANDOM
, $SECONDS
, ve $TMOUT
.
ps -p $$
Matthew Slattery'nin işaret ettiği gibi . İçin ksh
: echo $KSH_VERSION
veya echo ${.sh.version}
.
echo ${.sh.version}
"Bozuk Değiştirme" yi döndürür. Yukarıdaki çözümümü görün
ps -ef | grep …
Olarak ... ... Bu% 100 güvenilirdir” aracılığıyla basit bir normal ifade kullanma egrep
veya grep -e
kolayca güvenilirliğini kadar getirebilir için Tüm-niyet-ve-amaçlarla% 100: ps -ef | egrep "^\s*\d+\s+$$\s+"
. ^
Markaları emin biz satırın başından başlıyoruz, \d+
yediği UID kadar, $$
PID ile eşleşir ve \s*
ve \s+
hesap & diğer parçalar arasında boşluk sağlamak.
ps -ef | awk '$2==pid' pid=$$
ps -p $$
çözümlerin yer aldığı ps -ef
ve çalıştığı her yerde grep
( POSIX seçeneklerinips
destekleyen herhangi bir Unix varyantında ) çalışmalı ve başka yerlerde görünebilecek bir basamak dizisine hitap ederek ortaya çıkan yanlış pozitiflerden muzdarip olmayacaktır.
ps
bu da -p
kullanmanız gerekmeyebilir /bin/ps -p $$
.
$$
hariç fish
hangi ile kullanıma olurdu ps -p %self
.
/bin/ps
. ps
kolayca kurulabilir (aslında günümüzde oldukça normaldir) /usr/bin
. $(which ps) -p $$
daha iyi bir yol. Tabii ki, bu balıklarda ve muhtemelen diğer kabuklarda çalışmaz. Bence (which ps) -p %self
balıklarda.
readlink /proc/$$/exe
sh
tarafından taklit ise bash
, ps -p size /usr/bin/bash
bile çalıştırmak vermeksh
Deneyin
ps -p $$ -oargs=
veya
ps -p $$ -ocomm=
ps -o fname --no-headers $$
.
test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash
. (
-q
yerine -p
:SHELL=$(ps -ocomm= -q $$)
Yalnızca kullanıcının Bash ile bir komut dosyası çağırdığından emin olmak istiyorsanız:
if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
#!/bin/bash
: if [ ! -n "$BASH" ] ;then exec bash $0; fi
. Bu satırla komut dosyası ksh veya sh kullanılsa bile bash kullanılarak çalıştırılır. Kullanım durumumun komut satırı bağımsız değişkenlerine ihtiyacı yoktur, ancak $0
gerekirse sonra eklenebilir .
Deneyebilirsin:
ps | grep `echo $$` | awk '{ print $4 }'
Veya:
echo $SHELL
/pattern/ { action }
?
$SHELL
ortam değişkeni, geçerli kullanıcı için varsayılan olarak yapılandırılan bir kabuk içeriyor. Şu anda çalışan bir kabuğu yansıtmaz. Ayrıca ps -p $$
yanlış pozitifler nedeniyle $$' yi kullanmaktan daha iyidir.
awk
,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$SHELL
her zaman geçerli kabuğu göstermeniz gerekmez. Yalnızca çağrılacak varsayılan kabuğu yansıtır.
Yukarıdakileri test etmek için bash
, varsayılan kabuk olduğunu düşünün , deneyin echo $SHELL
ve sonra aynı terminalde, başka bir kabuğa ( örneğin KornShell (ksh)) girin ve deneyin $SHELL
. Her iki durumda da sonucu bash olarak göreceksiniz.
Geçerli kabuğun adını almak için Kullan cat /proc/$$/cmdline
. Ve tarafından çalıştırılabilir kabuk yolu readlink /proc/$$/exe
.
/proc
.
Şu anki mermiyi bulmak için basit bir numara var. Sadece rastgele bir dize yazın (bu bir komut değildir). Başarısız olur ve "bulunamadı" hatası döndürür, ancak satırın başında hangi kabuğun olduğunu söyler:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
echo 'aaaa' > script; chmod +x script; ./script
verir./script.sh: 1: aaaa: not found
Aşağıdakiler her zaman kullanılan gerçek kabuğu verir - kabuk ismini değil, gerçek yürütülebilir dosyanın adını alır (yani , vs. ksh93
yerine ksh
). Çünkü /bin/sh
, kullanılan gerçek kabuğu gösterecektir, yani dash
.
ls -l /proc/$$/exe | sed 's%.*/%%'
ls
Çıktının asla işlenmemesi gerektiğini söyleyen birçok kişi olduğunu biliyorum , ancak özel karakterlerle adlandırılan veya özel karakterlerle adlandırılan bir dizine yerleştirilen, kullandığınız bir kabuğa sahip olma olasılığı nedir? Halen durum buysa, farklı yapmanın başka örnekleri de vardır.
Toby Speight'ın işaret ettiği gibi , bu, bunu başarmanın daha doğru ve daha temiz bir yolu olacaktır:
basename $(readlink /proc/$$/exe)
/proc
. Tüm dünya bir Linux kutusu değil.
basename $(readlink /proc/$$/exe)
için ls
+ sed
+ echo
.
ash -> /bin/busybox
Birçok farklı yaklaşım denedim ve benim için en iyisi:
ps -p $$
Ayrıca Cygwin altında çalışır ve PID selamlaması olarak yanlış pozitif üretemez. Bazı temizlik işlemlerinde yalnızca yürütülebilir bir ad verir (yolu olan Cygwin altında):
ps -p $$ | tail -1 | awk '{print $NF}'
Ezberlemek zorunda kalmamanız için bir işlev oluşturabilirsiniz:
# Print currently active shell
shell () {
ps -p $$ | tail -1 | awk '{print $NF}'
}
... ve sonra sadece çalıştırın shell
.
Debian ve Cygwin altında test edildi.
ps
, tail
ve gawk
, cmd tanımlamıyor $$
kesinlikle düz cmd altında çalışma yapamaz bu yüzden 's PID gibi.
ps -p$$ -o comm=
? POSIX, tüm başlıkların boş olarak belirtilmesinin başlığı tamamen bastırdığını söylüyor. ps
Doğrudan yürütülen bir komut dosyasından (ör. #!/bin/sh
) Kaynaklandığımızda hala (tüm yanıtlar gibi ) başarısız oluyoruz .
Üst süreci yazdırma değişkenim:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
AWK sizin için yapabileceği zaman gereksiz uygulamaları çalıştırmayın.
awk
, ne zaman ps -p "$$" -o 'comm='
sizin için yapabilirim?
Kabuğu ve karşılık gelen sürümünü bulmanın birçok yolu vardır. İşte benim için çalışan birkaç kişi.
Basit
Hackish yaklaşımı
$> ******* (Rastgele bir dizi karakter yazın ve çıktıda kabuk adını alacaksınız. Benim durumumda -baş: bölüm2-a-örnek-izomorfik-uygulama: komut bulunamadı )
/bin/sh
POSIX standardını desteklemesi ve sisteminizde lsof
komutun yüklü olması şartıyla - lsof
bu durumda olası bir alternatif olabilir pid2path
- tam yolları yazdıran aşağıdaki komut dosyasını da kullanabilirsiniz (veya uyarlayabilirsiniz):
#!/bin/sh
# cat /usr/local/bin/cursh
set -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"; exit 1; }
export PATH
cmd="lsof"
env -i PATH="${PATH}" type "$cmd" 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }
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"; exit 1; }
lsofstr="`lsof -p $ppid`" ||
{ printf "%s\n" "lsof failed" "try: sudo lsof -p \`ps -p \$\$ -o ppid=\`"; exit 1; }
printf "%s\n" "${lsofstr}" |
LC_ALL=C awk -v var="${awkstr}" '$NF ~ var {print $NF}'
-i
(-> çevreyi yoksay) seçeneği nedeniyle bash'ta başarısız oluyor . ile başarısız: ->env
lsof
env -i PATH="${PATH}" type lsof
env: ‘type’: No such file or directory
Bash'in (belirli bir sürümünü) çalıştırdığınızı kontrol etmek istiyorsanız, bunu yapmanın en iyi yolu $BASH_VERSINFO
dizi değişkenini kullanmaktır . (Salt okunur) bir dizi değişkeni olarak, ortam içinde ayarlanamaz, böylece geçerli kabuktan (varsa) geldiğinden emin olabilirsiniz.
Ancak, Bash çağrıldığında farklı bir davranış gösterdiğinden sh
, $BASH
ortam değişkeninin bittiği yeri de kontrol etmeniz gerekir /bash
.
(Alt -
çizgi değil) ile işlev adlarını kullanan ve ilişkilendirilebilir dizilere (Bash 4'te eklenmiştir) bağlı olan bir komut dosyasında , aşağıdaki akıl kontrolü var (yardımcı kullanıcı hata iletisiyle):
case `eval 'echo $BASH@${BASH_VERSINFO[0]}' 2>/dev/null` in
*/bash@[456789])
# Claims bash version 4+, check for func-names and associative arrays
if ! eval "declare -A _ARRAY && func-name() { :; }" 2>/dev/null; then
echo >&2 "bash $BASH_VERSION is not supported (not really bash?)"
exit 1
fi
;;
*/bash@[123])
echo >&2 "bash $BASH_VERSION is not supported (version 4+ required)"
exit 1
;;
*)
echo >&2 "This script requires BASH (version 4+) - not regular sh"
echo >&2 "Re-run as \"bash $CMD\" for proper operation"
exit 1
;;
esac
İlk durumda özellikler için biraz paranoyak işlevsel kontrolü atlayabilir ve gelecekteki Bash sürümlerinin uyumlu olacağını varsayabilirsiniz.
Cevapların hiçbiri fish
kabuk ile çalışmadı ( $$
veya değişkenleri yok $0
).
(Üzerinde test benim için bu eserler sh
, bash
, fish
, ksh
, csh
, true
, tcsh
, ve zsh
; openSUSE 13.2):
ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
Bu komut aşağıdaki gibi bir dize çıktılar bash
. İşte sadece kullanıyorum ps
, tail
ve sed
(GNU extesions olmadan; eklemeyi deneyin --posix
kontrol etmek). Hepsi standart POSIX komutlarıdır. Eminim tail
kaldırılabilir, ama benim sed
fu bunu yapmak için yeterince güçlü değil.
Bana öyle geliyor ki, bu çözüm OS X üzerinde çalışmadığından çok taşınabilir değil. :(
sed: invalid option -- 'E'
basmak 3.2.51 ve tcsh 6.15.00
Çözümüm:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
Bu, farklı platformlarda ve kabuklarda taşınabilir olmalıdır. ps
Diğer çözümler gibi kullanır , ancak kabuğun her zaman son giriş olması için borudan ve kendisinden gelen gereksiz güveye güvenmez sed
veya awk
filtreler ps
. Bu şekilde, taşınabilir olmayan PID değişkenlerine veya doğru satırları ve sütunları seçmemize gerek kalmaz.
Bash, Z kabuğu ( zsh
) ve balık ile Debian ve macOS üzerinde test ettim ( farklı bir PID değişkeni kullandığından, özellikle balıklar için ifadeyi değiştirmeden bu çözümlerin çoğuyla çalışmaz).
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
grep $$
güvenilir değildir. ps -ef | awk -v pid=$$ '$2==pid { print $8 }'
iyidir, ama neden sadece kullanmıyorsunuz ps -p $$
?
Mac OS X'te (ve FreeBSD'de):
ps -p $$ -axco command | sed -n '$p'
zsh
ve bana verdi -bash
.
mutt
...: -b
/ Proc dizin yapısından herhangi bir PID için ilgili komut satırını okuyabildiğiniz için, "ps" çıkışından PID'ye gerek yoktur:
echo $(cat /proc/$$/cmdline)
Ancak, bu sadece basit olandan daha iyi olmayabilir:
echo $0
Aslında adından farklı bir kabuk çalıştırma hakkında bir fikir, daha önce aldığınız adı kullanarak kabuktan sürüm istemektir:
<some_shell> --version
sh
diğerleri yararlı bir şey verirken çıkış kodu 2 ile başarısız gibi görünüyor (ama ben onları yok beri hepsini doğrulamak mümkün değil):
$ sh --version
sh: 0: Illegal option --
echo $?
2
Bu çok temiz bir çözüm değil, ama ne istersen yapar.
# 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=false
for i in ${shells_array[*]}; do
if ! [ -z `printf $shell | grep $i` ] && ! $suited; then
shell=$i
suited=true
fi
done
echo $shell
}
getshell
Şimdi kullanabilirsiniz $(getshell) --version
.
Ancak bu sadece KornShell benzeri mermilerde (ksh) çalışır.
dash
, yash
kullandığınız takdirde, Normalde vbbash
, zsh
, ksh
böyle şeylere önem olmamalı -, neyse.
ksh
, özelliklerin çoğu çoğunlukla özelliklerin bir alt kümesidir bash
(bunu iyice kontrol etmedim ).
Kabuğunuzun Dash / Bash kullanıp kullanmadığını öğrenmek için aşağıdakileri yapın.
ls –la /bin/sh
:
sonuç /bin/sh -> /bin/bash
==> ise, kabuğunuz Bash kullanıyor demektir.
sonuç /bin/sh ->/bin/dash
==> ise, kabuğunuz Dash kullanıyor demektir.
Bash'ten Dash'e veya tersi yapmak istiyorsanız, aşağıdaki kodu kullanın:
ln -s /bin/bash /bin/sh
(kabuğu Bash olarak değiştir)
Not : Yukarıdaki komut / bin / sh zaten mevcutsa bir hatayla sonuçlanırsa, / bin / sh öğesini kaldırın ve tekrar deneyin.
Lütfen aşağıdaki komutu kullanın:
ps -p $$ | tail -1 | awk '{print $4}'
echo $SHELL
yapmaya çalıştığın şeyi iyi yapıyor. İkincisi de iyi değil, çünkü $SHELL
ortam değişkeni şu anda çalışan bir kabuk değil, geçerli bir kullanıcı için varsayılan kabuk içeriyor. Örneğin bash
varsayılan kabuk olarak ayarladıysam, çalıştır zsh
ve echo $SHELL
yazdırır bash
.
echo $SHELL
çöp olabilir: ~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
Bu, Red Hat Linux (RHEL), macOS, BSD ve bazı AIX'lerde iyi çalışır :
ps -T $$ | awk 'NR==2{print $NF}'
alternatif olarak, pstree mevcutsa aşağıdakiler de çalışmalıdır ,
pstree | egrep $$ | awk 'NR==2{print $NF}'
!
ikame yapıyor mu?) Muhtemelen kabuğun adını bulmaktan daha portatiftir. Yerel gelenek/bin/sh
, aslında kül, çizgi, bash, vb.