Üzerinde çalıştığım kabuğu nasıl belirleyebilirim?
psKomutun çı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?
psKomutun çı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, SHELLherhangi 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, psveya $0yaklaşı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 $PS3ve $PS4ayarlanır, oysa normal Bourne kabuğu ( sh) sadece vardır $PS1ve $PS2ayarlanır. Bu genellikle gibi görünüyor zor ayırt etmek - sadece arasındaki ortam değişkenleri tüm kümeye farkı shve kshbiz 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_VERSIONveya 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 egrepveya grep -ekolayca 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 -efve ç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.
psbu da -pkullanmanız gerekmeyebilir /bin/ps -p $$.
$$hariç fishhangi ile kullanıma olurdu ps -p %self.
/bin/ps. pskolayca 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 %selfbalıklarda.
readlink /proc/$$/exe
shtarafından taklit ise bash, ps -p size /usr/bin/bashbile ç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. (
-qyerine -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 $0gerekirse sonra eklenebilir .
Deneyebilirsin:
ps | grep `echo $$` | awk '{ print $4 }'
Veya:
echo $SHELL
/pattern/ { action }?
$SHELLortam 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] }'
$SHELLher 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 $SHELLve 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; ./scriptverir./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. ksh93yerine 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, tailve 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. psDoğ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/shPOSIX standardını desteklemesi ve sisteminizde lsofkomutun yüklü olması şartıyla - lsofbu 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: ->envlsofenv -i PATH="${PATH}" type lsofenv: ‘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_VERSINFOdizi 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, $BASHortam 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 fishkabuk 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, tailve sed(GNU extesions olmadan; eklemeyi deneyin --posixkontrol etmek). Hepsi standart POSIX komutlarıdır. Eminim tailkaldırılabilir, ama benim sedfu 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. psDiğ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 sedveya awkfiltreler 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'
zshve 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, yashkullandığınız takdirde, Normalde vbbash , zsh, kshbö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 $SHELLyapmaya çalıştığın şeyi iyi yapıyor. İkincisi de iyi değil, çünkü $SHELLortam 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 bashvarsayılan kabuk olarak ayarladıysam, çalıştır zshve echo $SHELLyazdı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.