Testowanie określonych możliwości (np. Czy dokonuje !podstawienia?) Jest prawdopodobnie bardziej przenośne niż znajdowanie nazwy powłoki. Lokalny zwyczaj może wymagać, abyś uruchomił coś o nazwie, /bin/shktóra może być popiołem, myślnikiem, uderzeniem itp.
msw
1
@msw: Wydaje się, że to dobry komentarz, ale nie zastanawiam się „jak?”.
nobar
Wydaje się, że nie ma prostej odpowiedzi na to pytanie. Jeśli nie możemy zapytać o powłokę, być może lepszym rozwiązaniem jest zawsze określenie powłoki. Nie jestem pewien, czy jest to zawsze możliwe, ale może łatwiej to osiągnąć, niż ludzie się domyślają.
@Aniket, nie tyle pomocy, ile mogłoby się wydawać - to dotyczy tylko interaktywnych procesów powłoki.
Toby Speight
Odpowiedzi:
793
Istnieją trzy podejścia do znalezienia nazwy pliku wykonywalnego bieżącej powłoki:
Zauważ, że wszystkie trzy podejścia można oszukać, jeśli plik wykonywalny powłoki jest /bin/sh, ale tak naprawdę bashna przykład zmienia się jego nazwę (co często się zdarza).
Zatem na twoje drugie pytanie, czy pswynik da wynik, odpowiada „ nie zawsze ”.
echo $0 - wypisze nazwę programu ... która w przypadku powłoki jest rzeczywistą powłoką.
ps -ef | grep $$ | grep -v grep- wyszuka bieżący identyfikator procesu na liście uruchomionych procesów. Ponieważ bieżącym procesem jest powłoka, zostanie on uwzględniony.
Nie jest to w 100% niezawodne, ponieważ możesz mieć inne procesy, których pslista zawiera taki sam numer jak identyfikator procesu powłoki, szczególnie jeśli ten identyfikator jest małą liczbą (na przykład, jeśli PID powłoki to „5”, możesz znaleźć procesy o nazwie „java5” lub „perl5” na tym samym grepwyjściu!). Jest to drugi problem związany z podejściem „ps”, poza tym, że nie można polegać na nazwie powłoki.
echo $SHELL- Ścieżka do bieżącej powłoki jest przechowywana jako SHELLzmienna dla dowolnej powłoki. Zastrzeżeniem tego jest to, że jeśli uruchomisz powłokę jawnie jako podproces (na przykład nie jest to twoja powłoka logowania), zamiast tego otrzymasz wartość powłoki logowania. Jeśli jest to możliwe, użyj metody pslub $0.
Jeśli jednak plik wykonywalny nie pasuje do twojej aktualnej powłoki (np. /bin/shJest to właściwie bash lub ksh), potrzebujesz heurystyki. Oto niektóre zmienne środowiskowe specyficzne dla różnych powłok:
$version jest ustawiony na tcsh
$BASH jest ustawiony na bash
$shell (małe litery) ustawiono na rzeczywistą nazwę powłoki w csh lub tcsh
$ZSH_NAME jest ustawiony na zsh
ksh ma $PS3i $PS4ustawia, podczas gdy normalna powłoka Bourne'a ( sh) ma $PS1i $PS2ustawia. To wydaje się jak zwykle najtrudniejsze do odróżnienia - z jedyną różnicę w całym zbiorze zmiennych środowiskowych pomiędzy shi kshmamy zainstalowany na Solaris Boxen jest $ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, i $TMOUT.
ps -p $$jak zauważa Matthew Slattery . Dla ksh: echo $KSH_VERSIONlub echo ${.sh.version}.
Wstrzymano do odwołania.
@Dennish - mój ksh w tej chwili nie ma ustawionego KSH_VERSION. i echo ${.sh.version}zwraca „Złe zastąpienie”. Zobacz moje rozwiązanie powyżej
DVK
3
„ ps -ef | grep …... To nie jest w 100% wiarygodne jako ...” Za pomocą prostego wyrażenia regularnego poprzez egreplub grep -emoże łatwo doprowadzić do wiarygodności dla-all-zamiarów-and-celów w 100%: ps -ef | egrep "^\s*\d+\s+$$\s+". W ^pilnuje, zaczynamy od początku linii, \d+zjada UID, urządzenie $$pasuje PID, a \s*i \s+konto dla & zapewnić odstępy między innymi częściami.
Slipp D. Thompson,
2
@ SlippD.Thompson nie działał w systemie GNU / Linux. Ale to wydaje się działać:ps -ef | awk '$2==pid' pid=$$
jarno
98
ps -p $$
powinien działać wszędzie tam, gdzie występują rozwiązania ps -ef i grepzrobić (na dowolnym wariancie Unix, który obsługuje opcje dla POSIXps ) i nie będzie cierpieć z powodu fałszywych alarmów wprowadzonych grepping na sekwencję cyfr, które mogą pojawić się w innym miejscu.
Niektóre powłoki mają swoje wbudowane wersje, psktórych może nie zrozumieć, -pwięc może być konieczne użycie /bin/ps -p $$.
Wstrzymano do odwołania.
12
Wszystkie muszle, które znam, rozumieją, z $$wyjątkiem fishktórych będziesz musiał użyć ps -p %self.
Wstrzymano do odwołania.
3
W rzeczywistości nie powinieneś polegać na trudnych ścieżkach, takich jak /bin/ps. psmożna łatwo zainstalować (obecnie jest to całkiem normalne) /usr/bin. $(which ps) -p $$to lepszy sposób. Oczywiście nie zadziała to u ryb i prawdopodobnie innych skorup. Myślę, że jest (which ps) -p %selfw rybach.
Aron Cederholm
1
W niektórych minimalnych systemach, takich jak cienki pojemnik dokujący Debiana, ps może nie być tam. W takim przypadku takie podejście nadal działa:readlink /proc/$$/exe
mxmlnkn
jeśli twój shjest naśladowany bash, ps -p daje ci /usr/bin/bashnawet uruchomić go jakosh
To jest ładne krótkie. Korzystałem z siebie ps -o fname --no-headers $$.
Anne van Rossum
Dzięki. Uważam, że jest to najlepsza opcja do użycia w skrypcie do ochrony określonych poleceń bash test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash. (Następny wiersz w moim skrypcie ma odpowiednik csh.)
craq
1
Odkryłem, że jeśli zrobisz to z podpowłoki, może to prowadzić do fałszywych dodatkowych linii poprzez dopasowanie PID rodzica, a także faktycznego procesu powłoki. W tym celu używam -qzamiast -p:SHELL=$(ps -ocomm= -q $$)
Steve
35
Jeśli chcesz tylko upewnić się, że użytkownik wywołuje skrypt za pomocą Bash:
if[!-n "$BASH"];then echo Please run this script $0 with bash;exit1;fi
To powinien być ten bliżej szczytu. Wielkie dzięki.
Alex Skrypnyk
4
Nie powinno być bliżej góry, ponieważ w ogóle nie odpowiada na pytanie. Jeśli pytanie brzmiałoby „Jak sprawdzić, czy skrypt działa pod bash”, głosuję na to.
David Ferenczy Rogožan
2
@DawidFerenczy - To pytanie jest jednak najlepszym wynikiem podczas wyszukiwania tego wyrażenia. Na dłuższą metę myślę, że o wiele ważniejsze jest, aby odpowiedzi odpowiadały na to, czego ludzie szukają, niż odpowiadały pierwotnemu pytaniu.
ArtOfWarfare
3
Ponadto zmienna $ BASH jest zdefiniowana w tcsh, jeśli tcsh jest wywoływany z bash
18446744073709551615
To bardzo przydatne, dziękuję. Wystarczy dostosować go trochę, stawiając to jako drugiej linii po #!/bin/bash: if [ ! -n "$BASH" ] ;then exec bash $0; fi. W tym wierszu skrypt jest uruchamiany przy użyciu bash, nawet jeśli zaczął używać ksh lub sh. Mój przypadek użycia nie wymaga argumentów z wiersza poleceń, ale można je dodać po nim, $0jeśli to konieczne.
Jaki jest sens grep, po którym następuje awk, kiedy /pattern/ { action }to zrobi?
Jens
# in zshell alias shell = 'echo $ {SHELL: t}'
SergioAraujo
4
$SHELLzmienna środowiskowa zawiera powłokę, która jest domyślnie skonfigurowana dla bieżącego użytkownika. Nie odzwierciedla powłoki, która jest obecnie uruchomiona. Lepiej jest także używać ps -p $$niż grepping $$ z powodu fałszywych wyników pozytywnych.
David Ferenczy Rogožan
Środowisko $ SHELL zmienna wskazuje na powłokę „macierzystą”, jak określono w specyfikacji POSIX: SHELL Ta zmienna reprezentuje nazwę ścieżki preferowanego przez użytkownika interpretera języka poleceń. Dlatego wartość $ SHELL może nie być bieżącą powłoką.
Theo
wszystko wewnątrz awk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
go2null
16
$SHELLnie zawsze musi pokazywać bieżącą powłokę. Odzwierciedla tylko domyślną powłokę, którą należy wywołać.
Aby przetestować powyższe, powiedzmy, że bashjest domyślną powłoką, spróbuj echo $SHELL, a następnie w tym samym terminalu, przejdź do innej powłoki ( na przykład KornShell (ksh)) i spróbuj $SHELL. W obu przypadkach zobaczysz wynik jako bash.
Aby uzyskać nazwę bieżącej powłoki, użyj cat /proc/$$/cmdline. I ścieżka do powłoki wykonywalnej przez readlink /proc/$$/exe.
ps jest najbardziej niezawodną metodą. Nie można zagwarantować, że zmienna środowiskowa SHELL zostanie ustawiona, a nawet jeśli tak, można ją łatwo sfałszować.
+1 $ SHELL jest domyślną powłoką dla programów, które muszą ją odrodzić. To niekoniecznie odzwierciedla aktualnie działającą powłokę.
Jim Lewis,
8
Mam prostą sztuczkę, aby znaleźć bieżącą powłokę. Wystarczy wpisać losowy ciąg znaków (który nie jest poleceniem). Nie powiedzie się i zwróci błąd „nie znaleziono”, ale na początku linii powie, która to powłoka:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Nic dobrego w skrypcie. echo 'aaaa' > script; chmod +x script; ./scriptdaje./script.sh: 1: aaaa: not found
szczupły
6
Poniższe zawsze podaje rzeczywistą używaną powłokę - pobiera nazwę rzeczywistego pliku wykonywalnego, a nie nazwę powłoki (tj. ksh93Zamiast kshitp.). Bo /bin/shpokaże rzeczywistą używaną powłokę, tj dash.
ls -l /proc/$$/exe | sed 's%.*/%%'
Wiem, że jest wielu, którzy mówią ls wyjściowe nigdy nie powinny być przetwarzane, ale jakie jest prawdopodobieństwo, że będziesz mieć używaną powłokę nazwaną znakami specjalnymi lub umieszczoną w katalogu o nazwach specjalnych? Jeśli nadal tak jest, istnieje wiele innych przykładów robienia tego inaczej.
Jak zauważył Toby Speight , byłby to bardziej właściwy i czystszy sposób osiągnięcia tego samego:
To tylko błędy we wszystkich Unices, które nie zapewniają /proc. Nie cały świat jest systemem Linux.
Jens
5
A jeśli jesteś na Linuksie, wolimy basename $(readlink /proc/$$/exe)do ls+ sed+ echo.
Toby Speight
1
To da nazwę rzeczywistego pliku wykonywalnego , a nie rzeczywistej powłoki . Gdy rzeczywista powłoka jest połączona jako aplet zajęty, powiedzmy ash -> /bin/busybox, to da / bin / busybox.
stepse
6
Próbowałem wielu różnych podejść i najlepsze dla mnie jest:
ps -p $$
Działa również pod Cygwinem i nie może generować fałszywych alarmów jako grepping PID. Po pewnym czyszczeniu wyświetla tylko nazwę pliku wykonywalnego (pod Cygwin ze ścieżką):
ps -p $$ | tail -1| awk '{print $NF}'
Możesz stworzyć funkcję, żebyś nie musiał jej zapamiętywać:
# Print currently active shell
shell (){
ps -p $$ | tail -1| awk '{print $NF}'}
W mojej konfiguracji (Cygwin | Windows 7) Twoja odpowiedź jest najlepsza, a ps -p $$ | ogon -1 | gawk „{print $ NF}” działa nawet z cmd bez $ bash. Uwaga gawk zamiast awk, ponieważ awk działa tylko z bash.
WebComer
@WebComer Przepraszamy, nie jestem pewien, co masz na myśli przez „ działa nawet z cmd bez $ bash ”. Nawet jeśli masz porty systemu Windows ps, taila gawkcmd nie definiuje się $$jako PID, więc zdecydowanie nie może działać pod zwykłym cmd.
David Ferenczy Rogožan
Dlaczego nie po prostu ps -p$$ -o comm=? POSIX mówi, że określenie wszystkich nagłówków pustych całkowicie pomija nagłówek. Nadal nie udaje nam się (podobnie jak wszystkie psodpowiedzi), gdy pozyskujemy bezpośrednio wykonany skrypt (np #!/bin/sh.).
Toby Speight
5
Mój wariant drukowania procesu nadrzędnego:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Nie uruchamiaj niepotrzebnych aplikacji, gdy AWK może to zrobić za Ciebie.
Po co uruchamiać niepotrzebne awk, kiedy ps -p "$$" -o 'comm='można to dla Ciebie zrobić?
Toby Speight
5
Istnieje wiele sposobów na znalezienie powłoki i odpowiadającej jej wersji. Oto kilka, które działały dla mnie.
Bezpośredni
$> echo $ 0 (Podaje nazwę programu. W moim przypadku wynikiem było -bash .)
$> $ SHELL (To zabierze Cię do powłoki, aw linii pojawi się nazwa i wersja powłoki. W moim przypadku bash3.2 $ .)
$> echo $ SHELL (To da ci ścieżkę do pliku wykonywalnego. W moim przypadku / bin / bash .)
$> $ SHELL --version (Daje to pełne informacje o oprogramowaniu powłoki z typem licencji)
Podstępne podejście
$> ******* (Wpisz zestaw losowych znaków, a na wyjściu otrzymasz nazwę powłoki. W moim przypadku -bash: rozdział2-a-sample-isomorphic-app: polecenie nie znaleziono )
Pod warunkiem, że /bin/shobsługujesz standard POSIX, a system ma lsofzainstalowaną komendę - lsofw tym przypadku może być alternatywą pid2path- możesz także użyć (lub dostosować) następującego skryptu, który wypisuje pełne ścieżki:
#!/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}'
to działa na ryby! ale dla mnie nie powiedzie się bash, z powodu opcji -i(-> ignore environment) envw linii, w której sprawdzasz lsofdostępność. kończy się niepowodzeniem: env -i PATH="${PATH}" type lsof->env: ‘type’: No such file or directory
hoijui
2
Jeśli chcesz tylko sprawdzić, czy korzystasz (konkretna wersja) Bash, najlepszym sposobem na to jest użycie $BASH_VERSINFOzmiennej tablicowej. Jako zmienna tablicowa (tylko do odczytu) nie można jej ustawić w środowisku, więc możesz być pewien, że pochodzi ona (jeśli w ogóle) z bieżącej powłoki.
Ponieważ jednak Bash ma inne zachowanie po wywołaniu jako sh, musisz również sprawdzić, czy $BASHzmienna środowiskowa kończy się na /bash.
W skrypcie, który napisałem, który używa nazw funkcji z -(bez podkreślenia) i zależy od tablic asocjacyjnych (dodanych w Bash 4), mam następującą kontrolę poprawności (z pomocnym komunikatem o błędzie użytkownika):
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
W pierwszym przypadku można pominąć nieco paranoiczne sprawdzenie działania funkcji i założyć, że przyszłe wersje Bash będą kompatybilne.
Żadna z odpowiedzi nie działała z fishpowłoką (nie ma zmiennych $$lub $0).
Działa to dla mnie (testowane na sh, bash, fish, ksh, csh, true, tcsh, i zsh; openSUSE 13.2):
ps | tail -n 4| sed -E '2,$d;s/.* (.*)/\1/'
To polecenie wyświetla ciąg podobny do bash. Tutaj jestem tylko przy użyciu ps, tailoraz sed(bez extesions GNU, spróbuj dodać --posixto sprawdzić). Wszystkie są standardowymi poleceniami POSIX. Jestem pewien, że tailmożna go usunąć, ale moje sedfu nie jest wystarczająco silne, aby to zrobić.
Wydaje mi się, że to rozwiązanie nie jest zbyt przenośne, ponieważ nie działa w systemie OS X. :(
Powinno to być przenośne na różnych platformach i powłokach. Wykorzystuje psjak inne rozwiązania, ale to nie zależy sedczy awki odfiltrowuje śmieci z orurowaniem i pssobie tak, że powłoka powinna być zawsze ostatni wpis. W ten sposób nie musimy polegać na nieprzenośnych zmiennych PID ani wybierać odpowiednich linii i kolumn.
Testowałem na Debianie i macOS z powłoką Bash, Z (zsh ) i fish (który nie działa z większością tych rozwiązań bez zmiany wyrażenia specjalnie dla ryb, ponieważ używa innej zmiennej PID).
Próbowałem tego podczas korzystania zshi dało mi to -bash.
user137369
W moim systemie (teraz), przetestowanym za pomocą bash i dash, ten powrót mutt...: -b
F. Hauri
1
Grepping PID z wyjścia „ps” nie jest potrzebny, ponieważ można odczytać odpowiedni wiersz polecenia dla dowolnego PID ze struktury katalogów / proc:
echo $(cat /proc/$$/cmdline)
Jednak nie może to być nic lepszego niż po prostu:
echo $0
Aby uruchomić właściwie inną powłokę niż wskazuje nazwa, jednym z pomysłów jest zażądanie wersji z powłoki przy użyciu wcześniej otrzymanej nazwy:
<some_shell> --version
sh wydaje się nie działać z kodem wyjścia 2, podczas gdy inni dają coś pożytecznego (ale nie jestem w stanie zweryfikować wszystkiego, ponieważ ich nie mam):
To nie jest bardzo czyste rozwiązanie, ale robi to, co chcesz.
# 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
„Działa to jednak tylko w przypadku powłok podobnych do ksh”. Czy mówisz, że muszę zweryfikować powłokę przed uruchomieniem tego? Hmm ...
jpaugh,
@jpaugh wykazy muszą być obsługiwane przez powłokę sourcing ten kod, który nie jest w przypadku dash, yashetc. Zwykle, jeśli używasz bash, zsh, ksh, cokolwiek - nie należy dbać o takich rzeczach.
theoden8
Więc liczysz bash jako „ksh-like”? Rozumiem. To ma więcej sensu
jpaugh
@ jpaugh, cóż, to miałem na myśli, ponieważ kshzestaw funkcji jest w większości podzbiorem bashfunkcji (chociaż nie sprawdziłem tego dokładnie).
theoden8
1
Wykonaj następujące czynności, aby wiedzieć, czy twoja powłoka używa Dash / Bash.
ls –la /bin/sh:
jeśli wynikiem jest /bin/sh -> /bin/bash==> Twoja powłoka używa Bash.
jeśli wynikiem jest /bin/sh ->/bin/dash==> Twoja powłoka używa Dash.
Jeśli chcesz zmienić Bash na Dash lub odwrotnie, użyj poniższego kodu:
ln -s /bin/bash /bin/sh (zmień powłokę na Bash)
Uwaga : Jeśli powyższe polecenie powoduje błąd: / bin / sh już istnieje, usuń / bin / sh i spróbuj ponownie.
Pierwszy to nonsens, echo $SHELLrobi to, co próbujesz zrobić i robi to dobrze. Drugi też nie jest dobry, ponieważ $SHELLzmienna środowiskowa zawiera domyślną powłokę dla bieżącego użytkownika, a nie aktualnie działającą powłokę. Jeśli mam na przykład bashUstaw jako domyślny shell, wykonanie zshi echo $SHELLbędziesz drukować bash.
!
podstawienia?) Jest prawdopodobnie bardziej przenośne niż znajdowanie nazwy powłoki. Lokalny zwyczaj może wymagać, abyś uruchomił coś o nazwie,/bin/sh
która może być popiołem, myślnikiem, uderzeniem itp.Odpowiedzi:
Istnieją trzy podejścia do znalezienia nazwy pliku wykonywalnego bieżącej powłoki:
Zauważ, że wszystkie trzy podejścia można oszukać, jeśli plik wykonywalny powłoki jest
/bin/sh
, ale tak naprawdębash
na przykład zmienia się jego nazwę (co często się zdarza).Zatem na twoje drugie pytanie, czy
ps
wynik da wynik, odpowiada „ nie zawsze ”.echo $0
- wypisze nazwę programu ... która w przypadku powłoki jest rzeczywistą powłoką.ps -ef | grep $$ | grep -v grep
- wyszuka bieżący identyfikator procesu na liście uruchomionych procesów. Ponieważ bieżącym procesem jest powłoka, zostanie on uwzględniony.Nie jest to w 100% niezawodne, ponieważ możesz mieć inne procesy, których
ps
lista zawiera taki sam numer jak identyfikator procesu powłoki, szczególnie jeśli ten identyfikator jest małą liczbą (na przykład, jeśli PID powłoki to „5”, możesz znaleźć procesy o nazwie „java5” lub „perl5” na tym samymgrep
wyjściu!). Jest to drugi problem związany z podejściem „ps”, poza tym, że nie można polegać na nazwie powłoki.echo $SHELL
- Ścieżka do bieżącej powłoki jest przechowywana jakoSHELL
zmienna dla dowolnej powłoki. Zastrzeżeniem tego jest to, że jeśli uruchomisz powłokę jawnie jako podproces (na przykład nie jest to twoja powłoka logowania), zamiast tego otrzymasz wartość powłoki logowania. Jeśli jest to możliwe, użyj metodyps
lub$0
.Jeśli jednak plik wykonywalny nie pasuje do twojej aktualnej powłoki (np.
/bin/sh
Jest to właściwie bash lub ksh), potrzebujesz heurystyki. Oto niektóre zmienne środowiskowe specyficzne dla różnych powłok:$version
jest ustawiony na tcsh$BASH
jest ustawiony na bash$shell
(małe litery) ustawiono na rzeczywistą nazwę powłoki w csh lub tcsh$ZSH_NAME
jest ustawiony na zshksh ma
$PS3
i$PS4
ustawia, podczas gdy normalna powłoka Bourne'a (sh
) ma$PS1
i$PS2
ustawia. To wydaje się jak zwykle najtrudniejsze do odróżnienia - z jedyną różnicę w całym zbiorze zmiennych środowiskowych pomiędzysh
iksh
mamy zainstalowany na Solaris Boxen jest$ERRNO
,$FCEDIT
,$LINENO
,$PPID
,$PS3
,$PS4
,$RANDOM
,$SECONDS
, i$TMOUT
.źródło
ps -p $$
jak zauważa Matthew Slattery . Dlaksh
:echo $KSH_VERSION
lubecho ${.sh.version}
.echo ${.sh.version}
zwraca „Złe zastąpienie”. Zobacz moje rozwiązanie powyżejps -ef | grep …
... To nie jest w 100% wiarygodne jako ...” Za pomocą prostego wyrażenia regularnego poprzezegrep
lubgrep -e
może łatwo doprowadzić do wiarygodności dla-all-zamiarów-and-celów w 100%:ps -ef | egrep "^\s*\d+\s+$$\s+"
. W^
pilnuje, zaczynamy od początku linii,\d+
zjada UID, urządzenie$$
pasuje PID, a\s*
i\s+
konto dla & zapewnić odstępy między innymi częściami.ps -ef | awk '$2==pid' pid=$$
ps -p $$
powinien działać wszędzie tam, gdzie występują rozwiązania
ps -ef
igrep
zrobić (na dowolnym wariancie Unix, który obsługuje opcje dla POSIXps
) i nie będzie cierpieć z powodu fałszywych alarmów wprowadzonych grepping na sekwencję cyfr, które mogą pojawić się w innym miejscu.źródło
ps
których może nie zrozumieć,-p
więc może być konieczne użycie/bin/ps -p $$
.$$
wyjątkiemfish
których będziesz musiał użyćps -p %self
./bin/ps
.ps
można łatwo zainstalować (obecnie jest to całkiem normalne)/usr/bin
.$(which ps) -p $$
to lepszy sposób. Oczywiście nie zadziała to u ryb i prawdopodobnie innych skorup. Myślę, że jest(which ps) -p %self
w rybach.readlink /proc/$$/exe
sh
jest naśladowanybash
, ps -p daje ci/usr/bin/bash
nawet uruchomić go jakosh
Próbować
lub
źródło
ps -o fname --no-headers $$
.test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash
. (Następny wiersz w moim skrypcie ma odpowiednik csh.)-q
zamiast-p
:SHELL=$(ps -ocomm= -q $$)
Jeśli chcesz tylko upewnić się, że użytkownik wywołuje skrypt za pomocą Bash:
źródło
#!/bin/bash
:if [ ! -n "$BASH" ] ;then exec bash $0; fi
. W tym wierszu skrypt jest uruchamiany przy użyciu bash, nawet jeśli zaczął używać ksh lub sh. Mój przypadek użycia nie wymaga argumentów z wiersza poleceń, ale można je dodać po nim,$0
jeśli to konieczne.Możesz spróbować:
Lub:
źródło
/pattern/ { action }
to zrobi?$SHELL
zmienna środowiskowa zawiera powłokę, która jest domyślnie skonfigurowana dla bieżącego użytkownika. Nie odzwierciedla powłoki, która jest obecnie uruchomiona. Lepiej jest także używaćps -p $$
niż grepping $$ z powodu fałszywych wyników pozytywnych.awk
,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$SHELL
nie zawsze musi pokazywać bieżącą powłokę. Odzwierciedla tylko domyślną powłokę, którą należy wywołać.Aby przetestować powyższe, powiedzmy, że
bash
jest domyślną powłoką, spróbujecho $SHELL
, a następnie w tym samym terminalu, przejdź do innej powłoki ( na przykład KornShell (ksh)) i spróbuj$SHELL
. W obu przypadkach zobaczysz wynik jako bash.Aby uzyskać nazwę bieżącej powłoki, użyj
cat /proc/$$/cmdline
. I ścieżka do powłoki wykonywalnej przezreadlink /proc/$$/exe
.źródło
/proc
.ps jest najbardziej niezawodną metodą. Nie można zagwarantować, że zmienna środowiskowa SHELL zostanie ustawiona, a nawet jeśli tak, można ją łatwo sfałszować.
źródło
Mam prostą sztuczkę, aby znaleźć bieżącą powłokę. Wystarczy wpisać losowy ciąg znaków (który nie jest poleceniem). Nie powiedzie się i zwróci błąd „nie znaleziono”, ale na początku linii powie, która to powłoka:
źródło
echo 'aaaa' > script; chmod +x script; ./script
daje./script.sh: 1: aaaa: not found
Poniższe zawsze podaje rzeczywistą używaną powłokę - pobiera nazwę rzeczywistego pliku wykonywalnego, a nie nazwę powłoki (tj.
ksh93
Zamiastksh
itp.). Bo/bin/sh
pokaże rzeczywistą używaną powłokę, tjdash
.Wiem, że jest wielu, którzy mówią
ls
wyjściowe nigdy nie powinny być przetwarzane, ale jakie jest prawdopodobieństwo, że będziesz mieć używaną powłokę nazwaną znakami specjalnymi lub umieszczoną w katalogu o nazwach specjalnych? Jeśli nadal tak jest, istnieje wiele innych przykładów robienia tego inaczej.Jak zauważył Toby Speight , byłby to bardziej właściwy i czystszy sposób osiągnięcia tego samego:
źródło
/proc
. Nie cały świat jest systemem Linux.basename $(readlink /proc/$$/exe)
dols
+sed
+echo
.ash -> /bin/busybox
, to da / bin / busybox.Próbowałem wielu różnych podejść i najlepsze dla mnie jest:
Działa również pod Cygwinem i nie może generować fałszywych alarmów jako grepping PID. Po pewnym czyszczeniu wyświetla tylko nazwę pliku wykonywalnego (pod Cygwin ze ścieżką):
Możesz stworzyć funkcję, żebyś nie musiał jej zapamiętywać:
... a następnie po prostu wykonaj
shell
.Został przetestowany pod Debianem i Cygwinem.
źródło
ps
,tail
agawk
cmd nie definiuje się$$
jako PID, więc zdecydowanie nie może działać pod zwykłym cmd.ps -p$$ -o comm=
? POSIX mówi, że określenie wszystkich nagłówków pustych całkowicie pomija nagłówek. Nadal nie udaje nam się (podobnie jak wszystkieps
odpowiedzi), gdy pozyskujemy bezpośrednio wykonany skrypt (np#!/bin/sh
.).Mój wariant drukowania procesu nadrzędnego:
Nie uruchamiaj niepotrzebnych aplikacji, gdy AWK może to zrobić za Ciebie.
źródło
awk
, kiedyps -p "$$" -o 'comm='
można to dla Ciebie zrobić?Istnieje wiele sposobów na znalezienie powłoki i odpowiadającej jej wersji. Oto kilka, które działały dla mnie.
Bezpośredni
Podstępne podejście
$> ******* (Wpisz zestaw losowych znaków, a na wyjściu otrzymasz nazwę powłoki. W moim przypadku -bash: rozdział2-a-sample-isomorphic-app: polecenie nie znaleziono )
źródło
Pod warunkiem, że
/bin/sh
obsługujesz standard POSIX, a system malsof
zainstalowaną komendę -lsof
w tym przypadku może być alternatywąpid2path
- możesz także użyć (lub dostosować) następującego skryptu, który wypisuje pełne ścieżki:źródło
-i
(-> ignore environment)env
w linii, w której sprawdzaszlsof
dostępność. kończy się niepowodzeniem:env -i PATH="${PATH}" type lsof
->env: ‘type’: No such file or directory
Jeśli chcesz tylko sprawdzić, czy korzystasz (konkretna wersja) Bash, najlepszym sposobem na to jest użycie
$BASH_VERSINFO
zmiennej tablicowej. Jako zmienna tablicowa (tylko do odczytu) nie można jej ustawić w środowisku, więc możesz być pewien, że pochodzi ona (jeśli w ogóle) z bieżącej powłoki.Ponieważ jednak Bash ma inne zachowanie po wywołaniu jako
sh
, musisz również sprawdzić, czy$BASH
zmienna środowiskowa kończy się na/bash
.W skrypcie, który napisałem, który używa nazw funkcji z
-
(bez podkreślenia) i zależy od tablic asocjacyjnych (dodanych w Bash 4), mam następującą kontrolę poprawności (z pomocnym komunikatem o błędzie użytkownika):W pierwszym przypadku można pominąć nieco paranoiczne sprawdzenie działania funkcji i założyć, że przyszłe wersje Bash będą kompatybilne.
źródło
Żadna z odpowiedzi nie działała z
fish
powłoką (nie ma zmiennych$$
lub$0
).Działa to dla mnie (testowane na
sh
,bash
,fish
,ksh
,csh
,true
,tcsh
, izsh
; openSUSE 13.2):To polecenie wyświetla ciąg podobny do
bash
. Tutaj jestem tylko przy użyciups
,tail
orazsed
(bez extesions GNU, spróbuj dodać--posix
to sprawdzić). Wszystkie są standardowymi poleceniami POSIX. Jestem pewien, żetail
można go usunąć, ale mojesed
fu nie jest wystarczająco silne, aby to zrobić.Wydaje mi się, że to rozwiązanie nie jest zbyt przenośne, ponieważ nie działa w systemie OS X. :(
źródło
sed: invalid option -- 'E'
bash 3.2.51 i tcsh 6.15.00Moje rozwiązanie:
Powinno to być przenośne na różnych platformach i powłokach. Wykorzystuje
ps
jak inne rozwiązania, ale to nie zależysed
czyawk
i odfiltrowuje śmieci z orurowaniem ips
sobie tak, że powłoka powinna być zawsze ostatni wpis. W ten sposób nie musimy polegać na nieprzenośnych zmiennych PID ani wybierać odpowiednich linii i kolumn.Testowałem na Debianie i macOS z powłoką Bash, Z (
zsh
) i fish (który nie działa z większością tych rozwiązań bez zmiany wyrażenia specjalnie dla ryb, ponieważ używa innej zmiennej PID).źródło
Od Skąd wiesz, jaka jest twoja obecna powłoka? .
źródło
grep $$
jest zawodne.ps -ef | awk -v pid=$$ '$2==pid { print $8 }'
jest lepszy, ale dlaczego nie po prostu użyćps -p $$
?W systemie Mac OS X (i FreeBSD):
źródło
zsh
i dało mi to-bash
.mutt
...: -bGrepping PID z wyjścia „ps” nie jest potrzebny, ponieważ można odczytać odpowiedni wiersz polecenia dla dowolnego PID ze struktury katalogów / proc:
Jednak nie może to być nic lepszego niż po prostu:
Aby uruchomić właściwie inną powłokę niż wskazuje nazwa, jednym z pomysłów jest zażądanie wersji z powłoki przy użyciu wcześniej otrzymanej nazwy:
sh
wydaje się nie działać z kodem wyjścia 2, podczas gdy inni dają coś pożytecznego (ale nie jestem w stanie zweryfikować wszystkiego, ponieważ ich nie mam):źródło
To nie jest bardzo czyste rozwiązanie, ale robi to, co chcesz.
Teraz możesz użyć
$(getshell) --version
.Działa to jednak tylko w przypadku powłok podobnych do KornShell (ksh).
źródło
dash
,yash
etc. Zwykle, jeśli używaszbash
,zsh
,ksh
, cokolwiek - nie należy dbać o takich rzeczach.ksh
zestaw funkcji jest w większości podzbiorembash
funkcji (chociaż nie sprawdziłem tego dokładnie).Wykonaj następujące czynności, aby wiedzieć, czy twoja powłoka używa Dash / Bash.
ls –la /bin/sh
:jeśli wynikiem jest
/bin/sh -> /bin/bash
==> Twoja powłoka używa Bash.jeśli wynikiem jest
/bin/sh ->/bin/dash
==> Twoja powłoka używa Dash.Jeśli chcesz zmienić Bash na Dash lub odwrotnie, użyj poniższego kodu:
ln -s /bin/bash /bin/sh
(zmień powłokę na Bash)Uwaga : Jeśli powyższe polecenie powoduje błąd: / bin / sh już istnieje, usuń / bin / sh i spróbuj ponownie.
źródło
I wymyśliłem to
źródło
Prosimy użyć następującego polecenia:
źródło
echo $SHELL
robi to, co próbujesz zrobić i robi to dobrze. Drugi też nie jest dobry, ponieważ$SHELL
zmienna środowiskowa zawiera domyślną powłokę dla bieżącego użytkownika, a nie aktualnie działającą powłokę. Jeśli mam na przykładbash
Ustaw jako domyślny shell, wykonaniezsh
iecho $SHELL
będziesz drukowaćbash
.echo $SHELL
mogą być śmieci:~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
Ten działa dobrze na Red Hat Linux (RHEL), macOS, BSD i niektórych systemach AIX :
alternatywnie, poniższy powinien również działać, jeśli pstree jest dostępny,
źródło