Jak mogę ustalić bieżącą powłokę, nad którą pracuję?
Czy wynik samego pspolecenia byłby wystarczający?
Jak można to zrobić w różnych wersjach Uniksa?
Jak mogę ustalić bieżącą powłokę, nad którą pracuję?
Czy wynik samego pspolecenia byłby wystarczający?
Jak można to zrobić w różnych wersjach Uniksa?
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ę 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.
echo ${.sh.version}zwraca „Złe zastąpienie”. Zobacz moje rozwiązanie powyżej
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.
ps -ef | awk '$2==pid' pid=$$
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.
psktórych może nie zrozumieć, -pwięc może być konieczne użycie /bin/ps -p $$.
$$wyjątkiem fishktórych będziesz musiał użyć ps -p %self.
/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.
readlink /proc/$$/exe
shjest naśladowany bash, ps -p daje ci /usr/bin/bashnawet uruchomić go jakosh
Próbować
ps -p $$ -oargs=
lub
ps -p $$ -ocomm=
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.)
-qzamiast -p:SHELL=$(ps -ocomm= -q $$)
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; exit 1; fi
#!/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.
Możesz spróbować:
ps | grep `echo $$` | awk '{ print $4 }'
Lub:
echo $SHELL
/pattern/ { action }to zrobi?
$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.
awk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$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.
/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ć.
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
echo 'aaaa' > script; chmod +x script; ./scriptdaje./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. 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:
basename $(readlink /proc/$$/exe)
/proc. Nie cały świat jest systemem Linux.
basename $(readlink /proc/$$/exe)do ls+ sed+ echo.
ash -> /bin/busybox, to da / bin / busybox.
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}'
}
... a następnie po prostu wykonaj shell.
Został przetestowany pod Debianem i Cygwinem.
ps, taila gawkcmd 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 wszystkie psodpowiedzi), gdy pozyskujemy bezpośrednio wykonany skrypt (np #!/bin/sh.).
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.
awk, kiedy ps -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 )
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/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(-> 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
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 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
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. :(
sed: invalid option -- 'E'bash 3.2.51 i tcsh 6.15.00
Moje rozwiązanie:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
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).
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
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):
ps -p $$ -axco command | sed -n '$p'
zshi dało mi to -bash.
mutt...: -b
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):
$ sh --version
sh: 0: Illegal option --
echo $?
2
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=false
for i in ${shells_array[*]}; do
if ! [ -z `printf $shell | grep $i` ] && ! $suited; then
shell=$i
suited=true
fi
done
echo $shell
}
getshell
Teraz możesz użyć $(getshell) --version .
Działa to jednak tylko w przypadku powłok podobnych do KornShell (ksh).
dash, yashetc. Zwykle, jeśli używasz bash, zsh, ksh, cokolwiek - nie należy dbać o takich rzeczach.
kshzestaw funkcji jest w większości podzbiorem bashfunkcji (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.
Prosimy użyć następującego polecenia:
ps -p $$ | tail -1 | awk '{print $4}'
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.
echo $SHELLmogą 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 :
ps -T $$ | awk 'NR==2{print $NF}'
alternatywnie, poniższy powinien również działać, jeśli pstree jest dostępny,
pstree | egrep $$ | awk 'NR==2{print $NF}'
!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.