Localiza localização do script de shell originado

7

É possível que um script de shell de origem conheça sua localização? Li como determinar o caminho para o script de shell originado , mas as respostas se concentram em bash e tcsh e falham se um shell POSIX é usado. $0 também não é a solução e produz resultados errados .

Uma solução não precisa ser 100% confiável. É improvável que o caminho contenha links rígidos ou simbólicos.

# sourcing the script should yield the absolute path to the script
. somedir/thescript

# within “thescript”
-> /tmp/foo/bar/somedir

Alguns antecedentes: O script faz parte de um aplicativo existente contendo dezenas de binários em um diretório bin em um local conhecido (varia por arquitetura) relativo ao script originado. Para usar o aplicativo, o usuário obtém o script que preenche o diretório bin para o PATH , portanto, os binários do aplicativo podem ser facilmente invocados no shell atual (qualquer shell que possa ser).

    
por Marco 15.10.2013 / 22:47

2 respostas

7

A localização do script de origem não está disponível, a menos que você esteja usando um shell que ofereça extensões para a especificação POSIX. Você pode testar isso com o seguinte snippet:

env -i PATH=/usr/bin:/bin sh -c '. ./included.sh' | grep included

onde included.sh contém

echo "$0"
set

No bash, o nome do script de origem está em $BASH_SOURCE . Em zsh (no modo de compatibilidade zsh, não no modo de compatibilidade sh ou ksh), está em $0 (observe que em uma função, $0 é o nome da função). Em pdksh e dash, não está disponível. Em ksh93, esse método não revela a solução, mas o caminho completo para o script incluído está disponível como ${.sh.file} .

Se precisar de bash ou ksh93 ou zsh for bom o suficiente, você pode usar este trecho:

if [ -n "$BASH_SOURCE" ]; then
  this_script=$BASH_SOURCE
elif [ -n "$ZSH_VERSION" ]; then
  setopt function_argzero
  this_script=$0
elif eval '[[ -n ${.sh.file} ]]' 2>/dev/null; then
  eval 'this_script=${.sh.file}'
else
  echo 1>&2 "Unsupported shell. Please use bash, ksh93 or zsh."
  exit 2
fi

Você pode tentar adivinhar a localização do script observando quais arquivos o shell abriu. Experimentalmente, isso parece funcionar com dash e pdksh, mas não com bash ou ksh93, que pelo menos para um script curto, fechou o arquivo de script no momento em que ele executou o script.

  open_file=$(lsof -F n -p $$ | sed -n '$s/^n//p')
  if [ -n "$open_file" ]; then
    # best guess: $open_file is this script
  fi

O script pode não ser o arquivo com o descritor de numeração mais alta, se o script for originado em um script complexo que está sendo reproduzido com redirecionamentos. Você pode querer percorrer os arquivos abertos. Isso não é garantido para funcionar de qualquer maneira. A única forma confiável de localizar um script de origem é usar bash, ksh93 ou zsh.

Se você puder alterar a interface, em vez de terceirizar seu script, peça ao script para imprimir um fragmento de shell a ser passado para eval no chamador. Isso é o que os scripts para definir variáveis de ambiente normalmente fazem. Ele permite que seu script seja escrito independentemente dos caprichos da configuração de shell e shell do chamador.

#!/bin/sh
FOO_DIR=$(dirname -- "$0")
cat <<EOF
FOO_DIR='$(printf %s "$FOO_DIR" | sed "s/'/'\''/g")'
PATH="\$PATH:$FOO_DIR/bin";
export FOO_DIR PATH
EOF

No chamador: eval "'/path/to/setenv'"

    
por 16.10.2013 / 03:43
0

Adicionando a resposta de Gilles, você PODERÁ conseguir o script de shell ( if $0 = ash ) através do /proc/$$ interface . Eu não sei o quão preciso isso é, mas /proc/$$/fd/11 parece sempre apontar para this_script com cinzas do BusyBox.

Fornecer isso como uma possível resposta para aqueles que se deparam com esta página (como eu).

A última resposta foi excluída - por isso, minha reivindicação para esse trabalho é testada em quatro plataformas HW diferentes (x86, ARM, XLP e powerpc). Todos dão a mesma resposta de fd / 11. Um readlink de /proc/$$/fd/11 produz meu script.

Andy

    
por 20.07.2018 / 20:06

Tags