Come posso determinare l'attuale shell su cui sto lavorando?
L'output del pscomando da solo sarebbe sufficiente?
Come può essere fatto in diversi gusti di Unix?
Come posso determinare l'attuale shell su cui sto lavorando?
L'output del pscomando da solo sarebbe sufficiente?
Come può essere fatto in diversi gusti di Unix?
Risposte:
Esistono tre approcci per trovare il nome dell'eseguibile della shell corrente:
Si noti che tutti e tre gli approcci possono essere ingannati se l'eseguibile della shell è /bin/sh, ma è davvero un rinominato bash, ad esempio (che accade spesso).
Quindi alla tua seconda domanda se l' psoutput farà sarà risposto con " non sempre ".
echo $0 - stamperà il nome del programma ... che nel caso della shell è la shell effettiva.
ps -ef | grep $$ | grep -v grep- questo cercherà l'ID del processo corrente nell'elenco dei processi in esecuzione. Poiché il processo corrente è la shell, verrà incluso.
Questo non è affidabile al 100%, poiché potresti avere altri processi la cui pslista include lo stesso numero dell'ID processo della shell, specialmente se quell'ID è un numero piccolo (ad esempio, se il PID della shell è "5", potresti trovare processi chiamati "java5" o "perl5" nello stesso grepoutput!). Questo è il secondo problema con l'approccio "ps", oltre a non poter fare affidamento sul nome della shell.
echo $SHELL- Il percorso della shell corrente viene memorizzato come SHELLvariabile per qualsiasi shell. L'avvertenza per questo è che se avvii esplicitamente una shell come sottoprocesso (per esempio, non è la tua shell di login), otterrai invece il valore della tua shell di login. Se questa è una possibilità, usa l' approccio pso $0.
Se, tuttavia, l'eseguibile non corrisponde alla shell reale (ad esempio, /bin/shè in realtà bash o ksh), è necessaria l'euristica. Ecco alcune variabili ambientali specifiche per varie shell:
$version è impostato su tcsh
$BASH è impostato su bash
$shell (minuscolo) è impostato sul nome della shell effettivo in csh o tcsh
$ZSH_NAME è impostato su zsh
ksh ha $PS3e $PS4imposta, mentre la normale shell Bourne ( sh) ha solo $PS1e $PS2imposta. Questo sembra in generale come la più difficile da distinguere - l' unica differenza in tutta la serie di variabili d'ambiente tra il she kshabbiamo installato su Solaris boxen è $ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, e $TMOUT.
echo ${.sh.version}restituisce "Sostituzione errata". Vedi la mia soluzione sopra
ps -ef | grep …... Questo è affidabile al 100% come ...” Utilizzando una semplice espressione regolare via egrepo grep -epuò facilmente portare l'affidabilità fino a per-tutte-intenti-e-fini 100%: ps -ef | egrep "^\s*\d+\s+$$\s+". Le ^marche sicuro che siamo a partire dall'inizio della linea, le \d+mangia l'UID, il $$corrisponde il PID, e la \s*e \s+rappresentano e garantiscono spazi tra le altre parti.
ps -ef | awk '$2==pid' pid=$$
ps -p $$
dovrebbe funzionare ovunque le soluzioni che coinvolgono ps -efe grepfanno (su qualsiasi variante Unix che supporti le opzioni POSIX perps ) e non soffriranno dei falsi positivi introdotti dal grepping per una sequenza di cifre che possono apparire altrove.
psche potrebbe non essere comprensibile, -pquindi potrebbe essere necessario utilizzarle /bin/ps -p $$.
$$tranne per le fishquali dovresti usare ps -p %self.
/bin/ps. pspotrebbe essere facilmente installato (attualmente è abbastanza normale al giorno d'oggi) /usr/bin. $(which ps) -p $$è un modo migliore. Naturalmente, questo non funzionerà nei pesci, e forse in alcuni altri gusci. Penso che sia (which ps) -p %selfnei pesci.
readlink /proc/$$/exe
shemulato da bash, ps -p ti dà /usr/bin/bashanche se lo esegui comesh
Provare
ps -p $$ -oargs=
o
ps -p $$ -ocomm=
ps -o fname --no-headers $$.
test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash. (La riga successiva nella mia sceneggiatura ha l'equivalente di csh.)
-qinvece di -p:SHELL=$(ps -ocomm= -q $$)
Se vuoi solo assicurarti che l'utente stia invocando uno script con 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. Con questa riga lo script viene eseguito usando bash anche se iniziato usando ksh o sh. Il mio caso d'uso non richiede argomenti da riga di comando, ma potrebbero essere aggiunti dopo, $0se necessario.
Puoi provare:
ps | grep `echo $$` | awk '{ print $4 }'
O:
echo $SHELL
/pattern/ { action }lo farà?
$SHELLLa variabile di ambiente contiene una shell, configurata come predefinita per un utente corrente. Non riflette una shell, che è attualmente in esecuzione. Inoltre è meglio usare ps -p $$che fare grepping $$ a causa di falsi positivi.
awk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$SHELLnon è necessario mostrare sempre la shell corrente. Riflette solo la shell predefinita da invocare.
Per provare quanto sopra, dire che bashè la shell predefinita, provare echo $SHELL, quindi nello stesso terminale, entrare in qualche altra shell ( ad esempio KornShell (ksh)) e provare $SHELL. Vedrai il risultato come bash in entrambi i casi.
Per ottenere il nome della shell corrente, utilizzare cat /proc/$$/cmdline. E il percorso per la shell eseguibile da readlink /proc/$$/exe.
/proc.
ps è il metodo più affidabile. Non è possibile impostare la variabile d'ambiente SHELL e, anche se lo è, può essere facilmente falsificata.
Ho un semplice trucco per trovare la shell corrente. Basta digitare una stringa casuale (che non è un comando). Fallirà e restituirà un errore "non trovato", ma all'inizio della riga dirà quale shell è:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
echo 'aaaa' > script; chmod +x script; ./scriptdà./script.sh: 1: aaaa: not found
Di seguito viene sempre fornita la shell effettiva utilizzata: ottiene il nome dell'eseguibile effettivo e non il nome della shell (ovvero ksh93anziché ksh, ecc.). Per /bin/sh, mostrerà l'effettiva shell utilizzata, cioè dash.
ls -l /proc/$$/exe | sed 's%.*/%%'
So che ci sono molti che affermano che l' lsoutput non dovrebbe mai essere elaborato, ma qual è la probabilità che tu abbia una shell che stai usando che è nominata con caratteri speciali o collocata in una directory chiamata con caratteri speciali? Se questo è ancora il caso, ci sono molti altri esempi di farlo diversamente.
Come sottolineato da Toby Speight , questo sarebbe un modo più corretto e più pulito di ottenere lo stesso:
basename $(readlink /proc/$$/exe)
/proc. Non tutto il mondo è una scatola Linux.
basename $(readlink /proc/$$/exe)a ls+ sed+ echo.
ash -> /bin/busybox, questo darà / bin / busybox.
Ho provato molti approcci diversi e il migliore per me è:
ps -p $$
Funziona anche con Cygwin e non può produrre falsi positivi come grepping PID. Con un po 'di pulizia, genera solo un nome eseguibile (sotto Cygwin con percorso):
ps -p $$ | tail -1 | awk '{print $NF}'
Puoi creare una funzione in modo da non doverla memorizzare:
# Print currently active shell
shell () {
ps -p $$ | tail -1 | awk '{print $NF}'
}
... e poi esegui shell.
È stato testato su Debian e Cygwin.
ps, taile gawk, cmd non definisce $$come è PID, quindi sicuramente non può funzionare sotto il semplice cmd.
ps -p$$ -o comm=? POSIX afferma che la specifica di tutte le intestazioni vuote elimina completamente l'intestazione. Stiamo ancora fallendo (come tutte le psrisposte) quando provengono da uno script eseguito direttamente (ad es #!/bin/sh.).
La mia variante sulla stampa del processo genitore:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Non eseguire applicazioni non necessarie quando AWK può farlo per te.
awk, quando ps -p "$$" -o 'comm='puoi farlo per te?
Esistono molti modi per scoprire la shell e la sua versione corrispondente. Eccone alcuni che hanno funzionato per me.
schietto
Approccio Hackish
$> ******* (Digita un set di caratteri casuali e nell'output otterrai il nome della shell. Nel mio caso -bash: capitolo2-a-sample-isomorphic-app: comando non trovato )
A condizione che /bin/shsupporti lo standard POSIX e che il tuo sistema abbia lsofinstallato il comando - una possibile alternativa a questo lsofpotrebbe essere pid2path- puoi anche usare (o adattare) il seguente script che stampa percorsi completi:
#!/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}'
-idell'opzione (-> ignora ambiente) envnella riga in cui controlli la lsofdisponibilità. fallisce con: env -i PATH="${PATH}" type lsof->env: ‘type’: No such file or directory
Se vuoi solo verificare che stai eseguendo (una versione particolare di) Bash, il modo migliore per farlo è usare la $BASH_VERSINFOvariabile array. Come variabile di array (di sola lettura) non può essere impostata nell'ambiente, quindi puoi essere sicuro che provenga (se non del tutto) dalla shell corrente.
Tuttavia, poiché Bash ha un comportamento diverso quando viene invocato come sh, è necessario verificare anche la $BASHfine della variabile di ambiente /bash.
In uno script che ho scritto che utilizza nomi di funzioni con -(non trattino basso) e dipende da array associativi (aggiunti in Bash 4), ho il seguente controllo di integrità (con utile messaggio di errore dell'utente):
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
Potresti omettere il controllo funzionale un po 'paranoico per le funzionalità nel primo caso e supporre che le future versioni di Bash sarebbero compatibili.
Nessuna delle risposte ha funzionato con la fishshell (non ha le variabili $$o $0).
Questo funziona per me (testato su sh, bash, fish, ksh, csh, true, tcsh, e zsh, openSUSE 13.2):
ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
Questo comando genera una stringa come bash. Qui sto solo usando ps, taile sed(senza estensioni GNU; prova ad aggiungere --posixper verificarlo). Sono tutti comandi POSIX standard. Sono sicuro che tailpuò essere rimosso, ma il mio sedfu non è abbastanza forte per farlo.
Mi sembra che questa soluzione non sia molto portatile in quanto non funziona su OS X. :(
sed: invalid option -- 'E'sulla bash 3.2.51 e tcsh 6.15.00
La mia soluzione:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
Questo dovrebbe essere portatile su diverse piattaforme e shell. Utilizza pscome altre soluzioni, ma non fa affidamento su sedo awke filtra la spazzatura dalle tubazioni e da psse stessa in modo che la shell sia sempre l'ultima voce. In questo modo non è necessario fare affidamento su variabili PID non portatili o selezionare le linee e le colonne giuste.
Ho testato su Debian e macOS con Bash, Z shell ( zsh) e fish (che non funziona con la maggior parte di queste soluzioni senza cambiare l'espressione specificamente per i pesci, perché usa una variabile PID diversa).
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
grep $$non è affidabile. ps -ef | awk -v pid=$$ '$2==pid { print $8 }'è meglio, ma perché non usarlo ps -p $$?
Su Mac OS X (e FreeBSD):
ps -p $$ -axco command | sed -n '$p'
zshHo provato questo durante l'utilizzo e mi ha dato -bash.
mutt...: -b
Non è necessario il grepping PID dall'output di "ps", poiché è possibile leggere la rispettiva riga di comando per qualsiasi PID dalla struttura della directory / proc:
echo $(cat /proc/$$/cmdline)
Tuttavia, potrebbe non essere migliore del semplice:
echo $0
Informazioni sull'esecuzione di una shell effettivamente diversa da quella indicata dal nome, un'idea è richiedere la versione dalla shell utilizzando il nome ottenuto in precedenza:
<some_shell> --version
sh sembra fallire con il codice di uscita 2 mentre altri danno qualcosa di utile (ma non sono in grado di verificare tutto poiché non li ho):
$ sh --version
sh: 0: Illegal option --
echo $?
2
Questa non è una soluzione molto pulita, ma fa quello che vuoi.
# 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
Adesso puoi usare $(getshell) --version.
dash, yashecc Normalmente, se si sta utilizzando bash, zsh, ksh, qualunque sia - non si dovrebbe preoccuparsi di queste cose.
kshil set di funzionalità è per lo più un sottoinsieme delle bashfunzionalità (non ho controllato bene questo però).
Fai quanto segue per sapere se la tua shell sta usando Dash / Bash.
ls –la /bin/sh:
se il risultato è /bin/sh -> /bin/bash==> Quindi la tua shell sta usando Bash.
se il risultato è /bin/sh ->/bin/dash==> Quindi la tua shell sta usando Dash.
Se vuoi passare da Bash a Dash o viceversa, usa il codice seguente:
ln -s /bin/bash /bin/sh (cambia shell in Bash)
Nota : se il comando sopra riportato genera un errore che dice, / bin / sh esiste già, rimuovere / bin / sh e riprovare.
Si prega di utilizzare il comando seguente:
ps -p $$ | tail -1 | awk '{print $4}'
echo $SHELLfa quello che stai cercando di fare e fallo bene. Anche il secondo non va bene, perché $SHELLla variabile di ambiente contiene una shell predefinita per un utente corrente, non una shell attualmente in esecuzione. Se ad esempio ho bashimpostato come shell predefinita, esegui zshe echo $SHELL, verrà stampato bash.
echo $SHELLpuò essere spazzatura: ~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
Questo funziona bene su Red Hat Linux (RHEL), macOS, BSD e alcuni AIX :
ps -T $$ | awk 'NR==2{print $NF}'
in alternativa, anche il seguente dovrebbe funzionare se è disponibile pstree ,
pstree | egrep $$ | awk 'NR==2{print $NF}'
!sostituzione?) È probabilmente più portabile che trovare il nome della shell. L'usanza locale potrebbe farti eseguire qualcosa di nome/bin/shche potrebbe effettivamente essere ash, dash, bash, ecc.