Existe uma maneira de um script de shell de origem descobrir o caminho para si mesmo? Estou preocupado principalmente com o bash, embora tenha alguns colegas de trabalho que usam o tcsh.
Suponho que talvez eu não tenha muita sorte aqui, pois o sourcing faz com que os comandos sejam executados no shell atual, portanto $0
ainda é a invocação do shell atual, não o script de origem. Meu melhor pensamento atualmente é fazer source $script $script
, para que o primeiro parâmetro posicional contenha as informações necessárias. Alguém tem uma maneira melhor?
Para ser claro, estou adquirindo o script, não o executando:
source foo.bash
Respostas:
Em
tcsh
,$_
no início do script conterá o local se o arquivo foi originado e$0
contém-lo se ele foi executado.No Bash:
fonte
> tcsh --version\n tcsh 6.14.00 (Astron) 2005-03-25 (i486-intel-linux) options wide,nls,dl,al,kan,rh,nd,color,filec
. Na medida em que o fornece de maneira não interativa, o arquivo de origem é incluído no arquivo pai como se realmente fosse parte dele (indistinguivelmente) como você mencionou na sua pergunta original. Eu acho que sua solução alternativa para os parâmetros posicionais é provavelmente a melhor abordagem. No entanto, a pergunta usual é "por que você quer fazer isso" e a resposta usual para a resposta é "não faça isso - faça isso em vez disso" onde "isso" costuma ser armazenado ....
esource
trabalharam de forma idêntica a este respeito. Observe que$_
deve ser acessado na primeira instrução do arquivo, caso contrário, ele conterá o último argumento do comando anterior. Eu gosto de incluir o shebang para minha própria referência, para que eu saiba qual shell deve ser e para o editor, para que ele use o destaque de sintaxe.source
, depois fazendo.
. Peço desculpas por ser incompetente. Eles são realmente idênticos. Enfim,$BASH_SOURCE
funciona.Eu acho que você poderia usar
$BASH_SOURCE
variável. Retorna o caminho que foi executado:Portanto, na próxima etapa, devemos verificar se o caminho é relativo ou não. Se não for relativo, está tudo bem. Se for, podemos verificar o caminho com
pwd
, concatenar com/
e$BASH_SOURCE
.fonte
source
pesquisas$PATH
se o nome fornecido não contiver a/
. A ordem de pesquisa depende das opções do shell, consulte o manual para obter detalhes.mydir="$(cd "$(dirname "$BASH_SOURCE")"; pwd)"
iria funcionar?Para detalhes e interesse dos pesquisadores, aqui está o que eles fazem ... É um wiki da comunidade, portanto, fique à vontade para adicionar os equivalentes de outros shell (obviamente, $ BASH_SOURCE será diferente).
test.sh:
test2.sh:
Bater:
Traço
Zsh
fonte
called=$_; echo $called; echo $_
? Isso não será impresso$_
duas vezes?$_
parâmetro especial: "Na inicialização do shell, defina o nome do caminho absoluto usado para chamar o shell ou script de shell que está sendo executado conforme transmitido no ambiente ou na lista de argumentos. Posteriormente, expande-se para o último argumento para o comando anterior, após a expansão. Também definido como o nome do caminho completo usado para chamar cada comando executado e colocado no ambiente exportado para esse comando. Ao verificar o correio, este parâmetro mantém o nome do arquivo de correio. "#! /bin/sh
que a torna inútil na origem. Isso iniciaria uma nova instância de/bin/sh
, definir variáveis e sair dessa instância, mantendo a instância de chamada inalterada.#
um script de shell é um comentário.#!
(shebang) tem seu significado especial apenas como a primeira linha de um script que é executado. Como a primeira linha de um arquivo originário, é apenas um comentário.Esta solução se aplica apenas ao bash e não ao tcsh. Observe que a resposta geralmente fornecida
${BASH_SOURCE[0]}
não funcionará se você tentar encontrar o caminho de dentro de uma função.Eu achei essa linha sempre funcionando, independentemente de o arquivo estar sendo originado ou executado como um script.
Se você deseja seguir os links simbólicos, use
readlink
o caminho acima, de forma recursiva ou não recursiva.Aqui está um script para testá-lo e compará-lo com outras soluções propostas. Invoque-o como
source test1/test2/test_script.sh
oubash test1/test2/test_script.sh
.A razão pela qual o one-liner funciona é explicada pelo uso da
BASH_SOURCE
variável de ambiente e de seu associadoFUNCNAME
.[Fonte: Manual do Bash]
fonte
Isso funcionou para mim no bash, dash, ksh e zsh:
Saída para esses reservatórios:
Tentei fazê-lo funcionar para o csh / tcsh, mas é muito difícil; Estou aderindo ao POSIX.
fonte
Fiquei um pouco confuso com a resposta do wiki da comunidade (de Shawn J. Goff), então escrevi um script para resolver as coisas. Sobre
$_
, eu encontrei o seguinte: Uso de_
como uma variável de ambiente passada para um comando . Como é uma variável de ambiente, é fácil testar seu valor incorretamente.Abaixo está o script, então é produzido. Eles também estão nessa essência .
test-shell-default-variables.sh
Saída de
./test-shell-default-variables.sh {da,ba,z,k}sh
O que aprendemos?
$BASH_SOURCE
$BASH_SOURCE
funciona no bash e somente no bash.$0
é quando o arquivo atual foi originado por outro arquivo. Nesse caso,$BASH_PROFILE
contém o nome do arquivo de origem, em vez do nome do arquivo de origem.$0
$0
tem o mesmo valor que$BASH_SOURCE
no bash.$_
$_
é deixado intocado pelo traço e pelo ksh.$_
decai para o último argumento da última chamada.$_
para "bash".$_
intocado. (ao procurar, é apenas o resultado da regra do "último argumento").Symlinks
ksh
sh
sh
, em relação a esses testes, ele se comporta como traço.fonte
Para o bash shell, achei a resposta de @Dennis Williamson mais útil, mas não funcionou no caso de
sudo
. Isto faz:fonte
Para tornar seu script compatível com bash e zsh, em vez de usar instruções if, você pode simplesmente escrever
${BASH_SOURCE[0]:-${(%):-%x}}
. O valor resultante será obtidoBASH_SOURCE[0]
quando definido e${(%):-%x}}
quando BASH_SOURCE [0] não estiver definido.fonte
tl; dr
script=$(readlink -e -- "${BASH_SOURCE}")
(para o bash obviamente)$BASH_SOURCE
casos de testearquivo fornecido
/tmp/source1.sh
source
o arquivo de maneiras diferentessource
de/tmp
source
de/
source
de diferentes caminhos relativos/tmp/a
e/var
a respeito de
$0
em todos os casos, se o script tiver o comando adicionado
então
source
o script sempre imprimeno entanto , se o script foi executado , por exemplo,
então
$0
seria o valor da string/tmp/source1.sh
.fonte
esta resposta descreve como
lsof
e um pouco de magia grep é a única coisa que parece ter uma chance de trabalhar para arquivos de origem aninhados no tcsh:fonte
Talvez isso não funcione com links simbólicos ou arquivos de origem, mas funcione para arquivos normais. Tomado como referência para. @kenorb Sem nome do diretório, link de leitura, BASH_SOURCE.
fonte
$0
fornece informações sobre o script em execução no momento , não sobre o código fonte.Na verdade, "dirname $ 0" fornecerá o caminho para o script, mas você deve interpretá-lo um pouco:
Você precisa se preparar para lidar com "." como o nome do diretório em algumas circunstâncias comuns. Eu experimentaria um pouco, pois lembro do dirname embutido no ksh fazendo as coisas de maneira um pouco diferente quando "." aparece em PATH.
fonte
$0
simplesmente contém "bash" para um shell interativo, e é tudo o que o script de origem vê.