Como posso determinar o shell atual em que estou trabalhando?
psSomente a saída do comando seria suficiente?
Como isso pode ser feito em diferentes sabores do Unix?
Como posso determinar o shell atual em que estou trabalhando?
psSomente a saída do comando seria suficiente?
Como isso pode ser feito em diferentes sabores do Unix?
Respostas:
Existem três abordagens para encontrar o nome do executável do shell atual:
Observe que todas as três abordagens podem ser enganadas se o executável do shell for /bin/sh, mas é realmente renomeado bash, por exemplo (o que geralmente acontece).
Assim, sua segunda pergunta sobre se a pssaída servirá é respondida com " nem sempre ".
echo $0 - imprimirá o nome do programa ... que, no caso do shell, é o shell real.
ps -ef | grep $$ | grep -v grep- isso procurará o ID do processo atual na lista de processos em execução. Como o processo atual é o shell, ele será incluído.
Isso não é 100% confiável, pois você pode ter outros processos cuja pslista inclui o mesmo número que o ID do processo do shell, especialmente se esse ID for um número pequeno (por exemplo, se o PID do shell for "5", você poderá encontrar processos chamados "java5" ou "perl5" na mesma grepsaída!). Este é o segundo problema com a abordagem "ps", além de não poder confiar no nome do shell.
echo $SHELL- O caminho para o shell atual é armazenado como a SHELLvariável para qualquer shell. A ressalva é que, se você iniciar um shell explicitamente como um subprocesso (por exemplo, não é o seu shell de login), obterá o valor do shell de login. Se for possível, use a abordagem psou $0.
Se, no entanto, o executável não corresponder ao seu shell real (por exemplo, /bin/shé realmente bash ou ksh), você precisará de heurísticas. Aqui estão algumas variáveis ambientais específicas para várias conchas:
$version está definido no tcsh
$BASH é definido no bash
$shell (minúsculo) é definido como o nome real do shell em csh ou tcsh
$ZSH_NAME está definido no zsh
O ksh possui $PS3e $PS4define, enquanto o shell Bourne normal ( sh) apenas possui $PS1e $PS2define. Isso geralmente parece ser o mais difícil de distinguir - a única diferença em todo o conjunto de variáveis de ambiente entre she kshtemos instalado no Solaris boxen é $ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, e $TMOUT.
echo ${.sh.version}retorna "Substituição incorreta". Veja minha solução acima
ps -ef | grep …… Isso não é 100% confiável como…” O uso de uma expressão regular simples via egrepou grep -epode facilmente trazer a confiabilidade até 100% para todos os efeitos - ps -ef | egrep "^\s*\d+\s+$$\s+". As ^marcas certeza de que estamos a partir do início da linha, os \d+come-se o UID, o $$corresponde ao PID, eo \s*e \s+conta para e garantir espaço em branco entre as outras partes.
ps -ef | awk '$2==pid' pid=$$
ps -p $$
deve funcionar em qualquer lugar que as soluções que envolvem ps -efe funcionem grep(em qualquer variante Unix que suporte opções POSIXps ) e não sofrerá com os falsos positivos introduzidos pelo grepping para uma sequência de dígitos que pode aparecer em outro lugar.
psque pode não ser entendida, -pportanto, você pode precisar usá-lo /bin/ps -p $$.
$$exceto as fishque você precisaria usar ps -p %self.
/bin/ps. pspoderia facilmente (atualmente é bastante normal hoje em dia) ser instalado no /usr/bin. $(which ps) -p $$é uma maneira melhor. Obviamente, isso não funcionará em peixes e, possivelmente, em outras conchas. Eu acho que é (which ps) -p %selfem peixe.
readlink /proc/$$/exe
shfor emulado por bash, ps -p lhe dará /usr/bin/bashaté você executá-lo como #sh
Tentar
ps -p $$ -oargs=
ou
ps -p $$ -ocomm=
ps -o fname --no-headers $$.
test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash. (A próxima linha no meu script tem o equivalente para csh.)
-qvez de -p:SHELL=$(ps -ocomm= -q $$)
Se você apenas deseja garantir que o usuário esteja chamando um script com o 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. Com esta linha, o script é executado usando o bash, mesmo que você comece a usar o ksh ou sh. Meu caso de uso não precisa de argumentos de linha de comando, mas eles podem ser adicionados depois, $0se necessário.
Podes tentar:
ps | grep `echo $$` | awk '{ print $4 }'
Ou:
echo $SHELL
/pattern/ { action }fará?
$SHELLA variável de ambiente contém um shell, que é configurado como padrão para um usuário atual. Ele não reflete um shell, que está sendo executado no momento. Também é melhor usar do ps -p $$que grepping $$ por causa de falsos positivos.
awk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$SHELLnem sempre é necessário mostrar o shell atual. Ele reflete apenas o shell padrão a ser chamado.
Para testar o que bashfoi dito acima, digamos que é o shell padrão, tente echo $SHELLe, no mesmo terminal, entre em outro shell ( KornShell (ksh), por exemplo) e tente $SHELL. Você verá o resultado como bash nos dois casos.
Para obter o nome do shell atual, use cat /proc/$$/cmdline. E o caminho para o shell executável por readlink /proc/$$/exe.
/proc.
ps é o método mais confiável. Não é garantido que a variável de ambiente SHELL seja configurada e, mesmo que seja, ela pode ser facilmente falsificada.
Eu tenho um truque simples para encontrar o shell atual. Basta digitar uma sequência aleatória (que não é um comando). Ele falhará e retornará um erro "não encontrado", mas no início da linha, ele dirá qual 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
O seguinte sempre fornecerá o shell real usado - ele obtém o nome do executável real e não o nome do shell (por exemplo, em ksh93vez de kshetc.). Pois /bin/sh, mostrará o shell atual usado, ie dash.
ls -l /proc/$$/exe | sed 's%.*/%%'
Sei que muitos dizem que a lssaída nunca deve ser processada, mas qual é a probabilidade de você usar um shell nomeado com caracteres especiais ou colocado em um diretório nomeado com caracteres especiais? Se esse ainda for o caso, há muitos outros exemplos de como fazê-lo de maneira diferente.
Conforme apontado por Toby Speight , essa seria uma maneira mais adequada e mais limpa de conseguir o mesmo:
basename $(readlink /proc/$$/exe)
/proc. Nem todo mundo é um Linux.
basename $(readlink /proc/$$/exe)a ls+ sed+ echo.
ash -> /bin/busybox, isso fornecerá / bin / busybox.
Eu tentei muitas abordagens diferentes e a melhor para mim é:
ps -p $$
Também funciona com Cygwin e não pode produzir falsos positivos como grepping de PID. Com alguma limpeza, ele gera apenas um nome executável (em Cygwin com path):
ps -p $$ | tail -1 | awk '{print $NF}'
Você pode criar uma função para não precisar memorizá-la:
# Print currently active shell
shell () {
ps -p $$ | tail -1 | awk '{print $NF}'
}
... e então apenas execute shell.
Foi testado no Debian e Cygwin.
ps, taile gawk, cmd não define $$como PID, então definitivamente não pode funcionar sob o cmd comum.
ps -p$$ -o comm=? O POSIX diz que especificar todos os cabeçalhos vazios suprime completamente o cabeçalho. Ainda estamos falhando (como todas as psrespostas) quando somos originados por um script executado diretamente (por exemplo #!/bin/sh).
Minha variante na impressão do processo pai:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Não execute aplicativos desnecessários quando o AWK puder fazer isso por você.
awk, quando ps -p "$$" -o 'comm='pode fazer isso por você?
Existem muitas maneiras de descobrir o shell e sua versão correspondente. Aqui estão alguns que funcionaram para mim.
Direto
Abordagem Hackish
$> ******* (Digite um conjunto de caracteres aleatórios e, na saída, você obterá o nome do shell. No meu caso -bash: chapter2-a-sample-isomorphic-app: comando não encontrado )
Desde que você /bin/shsuporte o padrão POSIX e seu sistema possua o lsofcomando instalado - uma possível alternativa possível lsofneste caso pid2path- você também pode usar (ou adaptar) o seguinte script que imprime caminhos completos:
#!/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) envna linha em que você verifica a lsofdisponibilidade. ele falha com: env -i PATH="${PATH}" type lsof->env: ‘type’: No such file or directory
Se você quiser apenas verificar se está executando (uma versão específica do) Bash, a melhor maneira de fazer isso é usar a $BASH_VERSINFOvariável de matriz. Como uma variável de matriz (somente leitura), ela não pode ser definida no ambiente, portanto, você pode ter certeza de que está vindo (se houver) do shell atual.
No entanto, como o Bash tem um comportamento diferente quando chamado como sh, você também precisa verificar a $BASHvariável de ambiente que termina com /bash.
Em um script que escrevi que usa nomes de funções com -(sem sublinhado) e depende de matrizes associativas (adicionadas no Bash 4), tenho a seguinte verificação de integridade (com mensagem de erro útil do usuário):
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
Você pode omitir a verificação funcional um tanto paranóica de recursos no primeiro caso e apenas assumir que versões futuras do Bash seriam compatíveis.
Nenhuma das respostas funcionou com o fishshell (ele não possui as variáveis $$ou $0).
Isso funciona para mim (testadas sh, bash, fish, ksh, csh, true, tcsh, e zsh; openSUSE 13.2):
ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
Este comando gera uma string como bash. Aqui eu só estou usando ps, taile sed(sem extesions GNU; tentar adicionar --posixpara verificá-lo). Todos eles são comandos POSIX padrão. Tenho certeza que tailpode ser removido, mas meu sedfu não é forte o suficiente para fazer isso.
Parece-me que esta solução não é muito portátil, pois não funciona no OS X. :(
sed: invalid option -- 'E'no bash 3.2.51 e tcsh 6.15.00
Minha solução:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
Isso deve ser portátil em diferentes plataformas e shells. Ele usa pscomo outras soluções, mas não depende sedou awkfiltra o lixo da tubulação e psele próprio, para que o shell sempre seja a última entrada. Dessa forma, não precisamos confiar em variáveis PID não portáveis ou escolher as linhas e colunas certas.
Eu testei no Debian e no macOS com Bash, Z shell ( zsh) e fish (que não funciona com a maioria dessas soluções sem alterar a expressão especificamente para fish, porque ele usa uma variável PID diferente).
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
grep $$não é confiável. ps -ef | awk -v pid=$$ '$2==pid { print $8 }'é melhor, mas por que não usar ps -p $$?
No Mac OS X (e FreeBSD):
ps -p $$ -axco command | sed -n '$p'
zsh, e isso me deu -bash.
mutt...: -b
Não é necessário receber o PID da saída de "ps", porque você pode ler a respectiva linha de comando para qualquer PID da estrutura de diretório / proc:
echo $(cat /proc/$$/cmdline)
No entanto, isso pode não ser melhor do que simplesmente:
echo $0
Sobre a execução de um shell realmente diferente do que o nome indica, uma idéia é solicitar a versão do shell usando o nome que você obteve anteriormente:
<some_shell> --version
sh parece falhar com o código de saída 2, enquanto outros fornecem algo útil (mas não consigo verificar tudo porque não os tenho):
$ sh --version
sh: 0: Illegal option --
echo $?
2
Esta não é uma solução muito limpa, mas faz o que você deseja.
# 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
Agora você pode usar $(getshell) --version.
Isso funciona, porém, apenas em conchas do tipo KornShell (ksh).
dash, yashetc. Normalmente, se você estiver usando bash, zsh, ksh, seja qual for - você deve se preocupam com essas coisas.
ksho conjunto de recursos é principalmente um subconjunto de bashrecursos (ainda não o verifiquei completamente).
Faça o seguinte para saber se o seu shell está usando o Dash / Bash.
ls –la /bin/sh:
se o resultado for /bin/sh -> /bin/bash==> Então seu shell está usando o Bash.
se o resultado for /bin/sh ->/bin/dash==> Então seu shell está usando o Dash.
Se você deseja mudar de Bash para Dash ou vice-versa, use o código abaixo:
ln -s /bin/bash /bin/sh (mude o shell para Bash)
Nota : Se o comando acima resultar em um erro dizendo: / bin / sh já existe, remova o / bin / sh e tente novamente.
Por favor, use o comando abaixo:
ps -p $$ | tail -1 | awk '{print $4}'
echo $SHELLfaz o que você está tentando fazer e faz bem. O segundo também não é bom, porque $SHELLa variável de ambiente contém shell padrão para um usuário atual, não um shell em execução no momento. Se eu tiver bashdefinido, por exemplo , como shell padrão, execute zshe echo $SHELL, ele será impresso bash.
echo $SHELLpode ser lixo: ~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
Este funciona bem no Red Hat Linux (RHEL), macOS, BSD e alguns AIXes :
ps -T $$ | awk 'NR==2{print $NF}'
alternativamente, o seguinte também deve funcionar se pstree estiver disponível,
pstree | egrep $$ | awk 'NR==2{print $NF}'
!substitui?) É provavelmente mais portátil do que encontrar o nome do shell. Costume local pode ter você correndo algo chamado/bin/shque poderia realmente ser cinzas, traço, festança, etc.