Come determinare la shell corrente su cui sto lavorando?

Come posso determinare la shell corrente su cui sto lavorando?

L’output del comando ps sarebbe sufficiente?

Come può essere fatto in diversi modi di UNIX?

  • Ci sono 3 approcci per trovare il nome dell’eseguibile della shell corrente:

    Si noti che tutti e 3 gli approcci possono essere ingannati se l’eseguibile della shell è /bin/sh ma in realtà si tratta di una bash ribattezzata, ad esempio (che spesso accade).

    Quindi la tua seconda domanda sul fatto che l’output di ps andrà a finire è ” non sempre “.

    1. echo $0 – stamperà il nome del programma … che nel caso della shell è la shell effettiva

    2. ps -ef | grep $$ | grep -v grep ps -ef | grep $$ | grep -v grep : cercherà l’ID del processo corrente nell’elenco dei processi in esecuzione. Poiché il processo corrente è shell, sarà incluso.

      Questo non è affidabile al 100%, poiché potresti avere ALTRI processi la cui lista ps include lo stesso numero dell’ID di processo della shell, specialmente se quell’ID è un piccolo # (ad esempio se il PID della shell è “5”, potresti trovare processi chiamati “java5” “o” perl5 “nella stessa uscita di grep !). Questo è il secondo problema con l’approccio “ps”, oltre a non poter contare sul nome della shell.

    3. echo $SHELL – Il percorso della shell corrente è memorizzato come variabile SHELL per qualsiasi shell. L’avvertimento per questo è che se si lancia una shell esplicitamente come sottoprocesso (ad esempio non è la shell di login), si otterrà invece il valore della propria shell di login. Se questa è una possibilità, usa l’approccio ps o $0 .


  • Se, tuttavia, l’eseguibile non corrisponde alla tua shell effettiva (es. /bin/sh è in realtà bash o ksh), hai bisogno dell’euristica. Ecco alcune variabili ambientali specifiche per varie shell:

    • $version è impostata su tcsh

    • $BASH è impostato su bash

    • $shell (in minuscolo) è impostato sul nome effettivo della shell in csh o tcsh

    • $ZSH_NAME è impostato su zsh

    • ksh ha set $PS3 e $PS4 , mentre la normale Bourne shell ( sh ) ha solo set $PS1 e $PS2 . Questo generalmente sembra il più difficile da distinguere – l’UNICA differenza nell’insieme delle variabili ambientali tra sh e ksh che abbiamo installato su Solaris è $ERRNO , $FCEDIT , $LINENO , $PPID , $PS3 , $PS4 , $RANDOM , $SECONDS , $TMOUT .

ps -p $$

Dovrebbe funzionare ovunque che le soluzioni che coinvolgono ps -ef e grep do (su qualsiasi variante di Unix che supporti le opzioni POSIX per ps ) e non soffriranno dei falsi positivi introdotti dall’avvio di una sequenza di cifre che potrebbero apparire altrove.

Provare

 ps -p $$ -oargs= 

o

 ps -p $$ -ocomm= 

Puoi provare:

 ps | grep `echo $$` | awk '{ print $4 }' 

O:

 echo $SHELL 

Se vuoi solo assicurarti che l’utente stia invocando lo script con bash:

 if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi 

$SHELL non ha bisogno di mostrare sempre la shell corrente. Riflette solo la shell di default da invocare.

Per provare quanto sopra, Say bash è la shell di default, prova echo $SHELL , poi nello stesso terminale, entra in qualche altra shell (ksh per esempio) e prova $SHELL , vedrai il risultato come bash in entrambi i casi.

Per ottenere il nome della shell corrente, utilizzare cat /proc/$$/cmdline E il percorso dell’eseguibile della shell da readlink /proc/$$/exe

ps è il metodo più affidabile. SHELL envar non è garantito per essere impostato e anche se lo è, può essere facilmente falsificato

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 linea dirà quale shell è:

 ksh: aaaaa: not found [No such file or directory] bash: aaaaa: command not found 

Questo darà sempre l’attuale shell usata – ottiene il nome dell’eseguibile reale e non il nome della shell (es. ksh93 invece di ksh ecc.) Per /bin/sh mostrerà la shell effettiva usata: cioè dash

 ls -l /proc/$$/exe | sed 's%.*/%%' 

So che ci sono molti che dicono che l’output di ls dovrebbe essere più recente, ma qual è la probabilità che tu abbia una shell che stai usando chiamata con caratteri speciali o inserita in una directory chiamata con caratteri speciali? Se ancora questo è il caso, qui ci sono molti altri esempi che lo fanno in modo diverso.

La mia variante sulla stampa del processo genitore.

 ps -p $$ | awk '$1 == PP {print $4}' PP=$$ 

Perché eseguire applicazioni non necessarie, quando ‘awk’ può farlo per te?

Se il tuo /bin/sh supporta lo standard POSIX e il tuo sistema ha il comando lsof installato – una ansible alternativa a lsof potrebbe in questo caso essere pid2path – puoi anche usare (o adattare) il seguente script che stampa i 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 "[email protected]" | 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}' 

Ho provato molti approcci diversi e quello migliore per me è:

ps -p $$

Funziona anche con Cygwin e non può produrre falsi positivi come greggio PID. Con un po ‘di pulizia, emette 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 .

Testato su Debian e Cygwin.

 echo $$ # Gives the Parent Process ID ps -ef | grep $$ | awk '{print $8}' #use the PID to see what the process is. 

da http://www.unix.com/unix-dummies-questions-answers/10390-how-do-you-know-what-your-current-shell.html

Su Mac OS X (e FreeBSD):

 ps -p $$ -axco command | sed -n '$p' 

Se vuoi solo controllare che tu stia correndo (una versione particolare di) Bash, il modo migliore per farlo è usare la variabile dell’array $BASH_VERSINFO . Come variabile dell’array (di sola lettura) non può essere impostato nell’ambiente, quindi puoi essere certo che stia arrivando (se non lo è) dalla shell corrente. Tuttavia, poiché Bash ha un comportamento diverso quando invocato come sh , è anche necessario verificare che la variabile di ambiente $BASH con /bash .

In uno script che ho scritto che usa nomi di funzioni con - (non underscore) e dipende da array associativi (aggiunti in Bash 4), ho il seguente controllo di integrità (con un utile messaggio di errore dell’utente):

 case `eval 'echo [email protected]${BASH_VERSINFO[0]}' 2>/dev/null` in */[email protected][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 ;; */[email protected][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 

È ansible omettere il controllo funzionale paranoico per le funzionalità nel primo caso e assumere che le future versioni di bash sarebbero compatibili.

Grepping PID dall’output di “ps” non è necessario perché puoi leggere la rispettiva riga di comando per qualsiasi PID dalla struttura della directory / proc:

 echo $(cat /proc/$$/cmdline) 

Tuttavia, questo potrebbe non essere migliore del semplice:

 echo $0 

A proposito dell’esecuzione di una shell diversa da quella indicata dal nome, l’idea è di richiedere la versione dalla shell usando il nome che hai precedentemente:

  --version 

sh sembra fallire con il codice di uscita 2 mentre altri danno qualcosa di utile (ma non sono in grado di verificare tutto dal momento che non li ho):

 $ sh --version sh: 0: Illegal option -- echo $? 2 

Nessuna delle risposte ha funzionato con la shell di fish (non ha 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 stringhe come bash . Sto usando qui solo ps , tail e sed (senza estensioni GNU, prova ad aggiungere --posix per controllarlo). Sono tutti comandi POSIX standard. Sono sicuro che la tail possa essere rimossa, ma il mio sed fu non abbastanza forte per farlo.

Mi sembra che questa soluzione non sia molto portabile dato che non funziona su OS X. 🙁

Questa non è una soluzione molto pulita, ma fa quello che vuoi.

Mi rendo conto che la risposta è un po ‘in ritardo in questo buon vecchio 2015, ma …

 #MUST BE SOURCED.. getshell() { local shell="`ps -p $$ | tail -1 | awk '{print $4}'`" shells_array=( # It is important that the shells are listed by the decrease of their length name. 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 

Ora puoi usare $(getshell) --version.

Questo funziona, però, solo su shell ksh-like.

La mia soluzione:

 ps -o command | grep -v -e "\" -e grep -e tail | tail -1 

Questo dovrebbe essere portatile su diverse piattaforms e shell. Usa ps come altre soluzioni, ma non si basa su sed o awk e filtra la junk dalle pipe e da ps stesso, così che la shell dovrebbe essere sempre l’ultima. In questo modo non è necessario fare affidamento su variabili PID non portabili o selezionare le linee e le colonne corrette.

Ho provato su Debian e MacOS con bash, zsh e fish (che non funziona con la maggior parte di queste soluzioni senza modificare l’espressione specificatamente per fish, perché usa una variabile PID diversa).

Ci sono molti modi per scoprire la shell e la sua versione corrispondente. Qui ci sono alcuni che hanno funzionato per me.

Dritto in avanti

  1. $> echo $ 0 (indica il nome del programma. Nel mio caso l’output era -bash )
  2. $> $ SHELL (Questo ti porta nella shell e nel prompt ottieni il nome e la versione della shell. Nel mio caso bash3.2 $ )
  3. $> echo $ SHELL (Questo ti darà il percorso eseguibile. Nel mio caso / bin / bash )
  4. $> $ SHELL –version (Questo fornirà informazioni complete sul software di shell con tipo di licenza)

Approccio Hackish

$> ******* (Digitare un set di caratteri casuali e nell’output si otterrà il nome della shell. Nel mio caso -bash: chapter2-a-sample-isomorphic-app: comando non trovato )

Si prega di utilizzare sotto il comando:

  # ps -p $$ | tail -1 | awk '{print $4}' 

Fai quanto segue per sapere se Shell sta usando DASH / BASH.

1) ls -la / bin / sh , se il risultato è / bin / sh -> / bin / bash ==> Allora la tua shell sta usando BASH.

se il risultato è / bin / sh -> / bin / dash ==> Allora la tua shell sta usando DASH.

Se si desidera passare da BASH a DASH o viceversa, utilizzare 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.

Questo funziona bene su RHEL, MacOS, BSD e alcuni AIX

 ps -T $$ | awk 'NR==2{print $NF}' 

in alternativa, il successivo dovrebbe funzionare anche se è disponibile pstree,

 pstree | egrep $$ | awk 'NR==2{print $NF}'