Como sei o nome do arquivo de script em um script Bash?

606

Como posso determinar o nome do arquivo de script Bash dentro do próprio script?

Como se meu script estivesse no arquivo runme.sh, como eu faria para exibir a mensagem "Você está executando o runme.sh" sem codificar isso?

Ma99uS
fonte
3
Semelhante [Pode um tell script bash o diretório sua armazenados em?] (Para stackoverflow.com/questions/59895/... )
Rodrigue
Para obter o diretório, consulte: Obtendo o diretório de origem de um script Bash de dentro .
Kenorb 19/07

Respostas:

631
me=`basename "$0"`

Para ler um link simbólico 1 , que geralmente não é o que você deseja (geralmente não deseja confundir o usuário dessa maneira), tente:

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"

IMO, isso produzirá resultados confusos. "Corri foo.sh, mas está dizendo que estou executando o bar.sh !? Deve ser um bug!" Além disso, um dos objetivos de ter links simbólicos com nomes diferentes é fornecer funcionalidades diferentes com base no nome que ele chama (pense em gzip e gunzip em algumas plataformas).


1 Ou seja, para resolver links simbólicos de modo que, quando o usuário executa o foo.shque é realmente um link simbólico bar.sh, você deseja usar o nome resolvido em bar.shvez de foo.sh.

Tanktalus
fonte
40
$ 0 fornece o nome pelo qual o script foi chamado, não o caminho real do arquivo de script real.
22430 Chris Conway
4
Funciona a menos que você esteja sendo chamado via link simbólico. Mas, mesmo assim, geralmente é o que você deseja, IME.
Tanktalus 10/10/08
78
Não funciona para scripts originados em oposição a invocados.
Charles Duffy
1
@ Charles Duffy: Veja a resposta de Dimitre Radoulov abaixo .
Serge Wautier
8
-1, 1. o readlink percorre apenas um link simbólico profundo, 2. $0no primeiro exemplo, está sujeito à divisão de palavras, 3. $0é passado para o nome da base, o readlink e o eco em uma posição que permite que seja tratado como uma opção de linha de comando . Sugiro em vez disso me=$(basename -- "$0")ou muito mais eficientemente às custas da legibilidade me=${0##*/},. Para links simbólicos, me=$(basename -- "$(readlink -f -- "$0")")assumindo os utilitários gnu, caso contrário, será um script muito longo que não escreverei aqui.
Score_Under
246
# ------------- SCRIPT ------------- # # ------------- CHAMADO ------ ------- #

#!/bin/bash

echo
echo "# arguments called with ---->  ${@}     "
echo "# \$1 ---------------------->  $1       "
echo "# \$2 ---------------------->  $2       "
echo "# path to me --------------->  ${0}     "
echo "# parent path -------------->  ${0%/*}  "
echo "# my name ------------------>  ${0##*/} "
echo
exit



# Observe na próxima linha, o primeiro argumento é chamado entre aspas duplas, # e simples, pois contém duas palavras


$   / misc / shell_scripts / check_root / show_parms . sh "'olá, lá'" "'william'" 

# ------------- RESULTADOS ------------- #

# argumentos chamados com ---> 'olá lá' 'william' # $ 1 ----------------------> 'olá lá' # $ 2 ---- ------------------> 'william' # path to me --------------> / misc / shell_scripts / check_root / show_parms. sh # caminho pai -------------> / misc / shell_scripts / check_root # meu nome -----------------> show_parms.sh






# ------------- FIM ------------- #
Bill Hernandez
fonte
11
@NickC consulte Remoção de substring
cychoi
1
Como obtenho apenas show_params, ou seja, o nome sem nenhuma extensão opcional?
Acumenus 08/07/2015
Não funciona caso o script seja chamado de outra pasta. O caminho está incluído no ${0##*/}. Testado usando GitBash.
AlikElzin-kilaka 30/07
1
O exemplo acima não funcionou para mim a partir de um script .bash_login, mas a solução Dimitre Radoulov do $ BASH_SOURCE funciona muito bem.
John
@ John Certamente você quer dizer .bash_profile ? Ou, alternativamente, .bashrc ? Você deve saber, porém, que existem algumas diferenças sutis na maneira como são invocadas / originadas. Estou muito cansado, mas se estiver pensando direito, esse provavelmente será o problema. Um lugar que importa é se você estiver conectado a um sistema remotamente, por exemplo, ssh versus no sistema local.
Pryftan
193

Com bash> = 3, o seguinte funciona:

$ ./s
0 is: ./s
BASH_SOURCE is: ./s
$ . ./s
0 is: bash
BASH_SOURCE is: ./s

$ cat s
#!/bin/bash

printf '$0 is: %s\n$BASH_SOURCE is: %s\n' "$0" "$BASH_SOURCE"
Dimitre Radoulov
fonte
24
Ótimo! Essa é a resposta que funciona tanto para ./scrip.sh e fonte ./script.sh
zhaorufei
4
É isso que eu quero, e é fácil usar " dirname $BASE_SOURCE" para obter o diretório que os scripts localizaram.
Larry Cai
2
Quase aprendi essa diferença da maneira mais difícil ao escrever um script de exclusão automática. Felizmente 'rm' era alias para 'rm -i' :)
kervin
de qualquer maneira para o. ./s para obter o nome ./s em vez de bash? Descobri que $ 1 não é sempre definido como ./s ...
David Mokon de Bond
1
Está em BASH_SOURCE , não está?
Dimitre Radoulov
69

$BASH_SOURCE fornece a resposta correta ao obter o script.

No entanto, isso inclui o caminho para obter apenas o nome do arquivo dos scripts, use:

$(basename $BASH_SOURCE) 
Zainka
fonte
2
Esta resposta é IMHO a melhor porque a solução utiliza código de auto-documentação. $ BASH_SOURCE é totalmente compreensível sem ler qualquer documentação enquanto por exemplo $ {0 ## * /} não é
Andreas M. Oberheim
Essa resposta é de mais valor, pois acredito que, se funcionarmos como . <filename> [arguments], $0daria o nome do shell do chamador. Bem, pelo menos no OSX, com certeza.
Mihir
68

Se o nome do script tiver espaços, uma forma mais robusta é usar "$0"ou "$(basename "$0")"- ou no MacOS: "$(basename \"$0\")". Isso impede que o nome seja mutilado ou interpretado de qualquer forma. Em geral, é uma boa prática sempre citar dois nomes de variáveis ​​no shell.

Josh Lee
fonte
2
+1 para resposta direta + conciso. se precisar de recursos de link simbólico, sugiro ver: resposta de Travis B. Hartwell.
Trevor Boyd Smith
26

Se você quiser sem o caminho, você usaria ${0##*/}

Mr. Muskrat
fonte
E se eu quiser, sem nenhuma extensão de arquivo opcional?
Acumenos
Para remover uma extensão, você pode tentar "$ {VARIABLE% .ext}" em que VARIABLE é o valor que você obteve de $ {0 ## * /} e ".ext" é a extensão que você deseja remover.
BrianV
19

Para responder a Chris Conway , no Linux (pelo menos), você faria o seguinte:

echo $(basename $(readlink -nf $0))

O readlink imprime o valor de um link simbólico. Se não for um link simbólico, ele imprime o nome do arquivo. -n diz para não imprimir uma nova linha. -f diz para seguir o link completamente (se um link simbólico fosse um link para outro link, ele também resolveria esse).

Travis B. Hartwell
fonte
2
-n é inofensivo, mas não é necessário, porque a estrutura $ (...) a cortará.
zhaorufei
16

Descobri que essa linha sempre funciona, independentemente de o arquivo estar sendo originado ou executado como um script.

echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"

Se você deseja seguir os links simbólicos, use readlinko caminho acima, recursivamente ou não recursivamente.

A razão pela qual o one-liner funciona é explicada pelo uso da BASH_SOURCEvariável de ambiente e de seu associado FUNCNAME.

BASH_SOURCE

Uma variável de matriz cujos membros são os nomes de arquivos de origem em que os nomes das funções de shell correspondentes na variável de matriz FUNCNAME são definidos. A função shell $ {FUNCNAME [$ i]} é definida no arquivo $ {BASH_SOURCE [$ i]} e é chamada a partir de $ {BASH_SOURCE [$ i + 1]}.

FUNCNAME

Uma variável de matriz que contém os nomes de todas as funções de shell atualmente na pilha de chamadas de execução. O elemento com índice 0 é o nome de qualquer função shell em execução no momento. O elemento mais baixo (aquele com o índice mais alto) é "principal". Essa variável existe apenas quando uma função shell está em execução. As atribuições a FUNCNAME não têm efeito e retornam um status de erro. Se FUNCNAME estiver desativado, ele perderá suas propriedades especiais, mesmo que seja redefinido posteriormente.

Essa variável pode ser usada com BASH_LINENO e BASH_SOURCE. Cada elemento de FUNCNAME possui elementos correspondentes em BASH_LINENO e BASH_SOURCE para descrever a pilha de chamadas. Por exemplo, $ {FUNCNAME [$ i]} foi chamado do arquivo $ {BASH_SOURCE [$ i + 1]} na linha número $ {BASH_LINENO [$ i]}. O chamador interno exibe a pilha de chamadas atual usando essas informações.

[Fonte: Manual do Bash]

gkb0986
fonte
2
Funciona se você buscar no arquivo a (suponha que ao conteúdo seja echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}") de uma sessão interativa - ao caminho será o mesmo. Mas se você escrever um script bcom source anele e correr ./b, ele vai voltar b's caminho.
PSKocik
12

Essas respostas estão corretas para os casos que afirmam, mas ainda existe um problema se você executar o script de outro script usando a palavra-chave 'source' (para que seja executada no mesmo shell). Nesse caso, você recebe os $ 0 do script de chamada. E, neste caso, não acho possível obter o nome do próprio script.

Este é um caso extremo e não deve ser levado muito a sério. Se você executar o script diretamente de outro script (sem 'fonte'), usar $ 0 funcionará.

Jim Dodd
fonte
2
Você tem um argumento muito bom. Não é um IMO de caso extremos. Porém, existe uma solução: veja a resposta de Dimitre Radoulov acima
Serge Wautier
10

Como alguns comentários perguntaram sobre o nome do arquivo sem extensão, eis um exemplo de como fazer isso:

FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}

Aproveitar!

Simon Mattes
fonte
9

Re: Resposta do Tanktalus (aceita) acima, uma maneira um pouco mais limpa é usar:

me=$(readlink --canonicalize --no-newline $0)

Se seu script foi originado de outro script bash, você pode usar:

me=$(readlink --canonicalize --no-newline $BASH_SOURCE)

Concordo que seria confuso remover referências de links simbólicos se seu objetivo é fornecer feedback ao usuário, mas há ocasiões em que você precisa obter o nome canônico para um script ou outro arquivo, e esse é o melhor caminho.

simon
fonte
1
Obrigado por sourcenomes de scripts d.
Fredrick Gauss
8

Você pode usar $ 0 para determinar o nome do seu script (com o caminho completo) - para obter o nome do script apenas você pode aparar essa variável com

basename $0
VolkA
fonte
8

se o seu invocar script de shell como

/home/mike/runme.sh

$ 0 é o nome completo

 /home/mike/runme.sh

basename $ 0 obterá o nome do arquivo base

 runme.sh

e você precisa colocar esse nome básico em uma variável como

filename=$(basename $0)

e adicione seu texto adicional

echo "You are running $filename"

então seus scripts como

/home/mike/runme.sh
#!/bin/bash 
filename=$(basename $0)
echo "You are running $filename"
LawrenceLi
fonte
7
this="$(dirname "$(realpath "$BASH_SOURCE")")"

Isso resolve links simbólicos (o realpath faz isso), manipula espaços (aspas duplas fazem isso) e localiza o nome do script atual mesmo quando originado (. ./Myscript) ou chamado por outros scripts ($ BASH_SOURCE lida com isso). Depois de tudo isso, é bom salvar isso em uma variável de ambiente para reutilização ou para cópia fácil em outro lugar (this =) ...

jcalfee314
fonte
3
FYI realpathnão é um comando BASH interno. É um executável autônomo que está disponível apenas em algumas distribuições
StvnW
4

Em bashvocê pode obter o nome do arquivo de script usando $0. Geralmente $1, $2etc , devem acessar os argumentos da CLI. Da mesma forma $0é acessar o nome que aciona o script (nome do arquivo de script).

#!/bin/bash
echo "You are running $0"
...
...

Se você chamar o script com o caminho como, /path/to/script.shentão $0também fornecerá o nome do arquivo com o caminho. Nesse caso, precisa usar $(basename $0)para obter apenas o nome do arquivo de script.

rashok
fonte
3
echo "$(basename "`test -L ${BASH_SOURCE[0]} \
                   && readlink ${BASH_SOURCE[0]} \
                   || echo ${BASH_SOURCE[0]}`")"
ecwpz91
fonte
2

$0não responde à pergunta (como eu a entendo). Uma demonstração:

$ cat script.sh
#! / bin / sh
eco `basename $ 0`
$ ./script.sh 
script.sh
$ ln script.sh linktoscript
$ ./linktoscript 
linktoscript

Como se consegue ./linktoscriptimprimir script.sh?

[EDIT] Por @ ephemient nos comentários acima, embora a coisa do link simbólico possa parecer artificial, é possível mexer com $0isso para que não represente um recurso do sistema de arquivos. O OP é um pouco ambíguo sobre o que ele queria.

Chris Conway
fonte
acrescentou resposta a esta a minha resposta acima, mas eu discordo que isso é o que realmente queria (ou que você deve querer que, salvo algumas circunstâncias atenuantes que eu não posso atualmente braças)
Tanktalus
2
Eu acho que imprimir linktoscript em vez de script.sh é um recurso, não um bug. Vários comandos unix usam seu nome para alterar seu comportamento. Um exemplo é vi / ex / view.
Mouviciel 12/03/09
@Tanktalus: Há casos em que você deseja que o comportamento mude com base na localização real do arquivo - em um projeto anterior, eu tinha um script "Ramificação ativa", que ligaria o caminho para várias ferramentas da ramificação em que estive. trabalhando em; essas ferramentas poderiam descobrir em qual diretório eles foram retirados para executar nos arquivos corretos.
Andrew Aylett
2

Informação graças a Bill Hernandez. Eu adicionei algumas preferências que estou adotando.

#!/bin/bash
function Usage(){
    echo " Usage: show_parameters [ arg1 ][ arg2 ]"
}
[[ ${#2} -eq 0 ]] && Usage || {
    echo
    echo "# arguments called with ---->  ${@}     "
    echo "# \$1 ----------------------->  $1       "
    echo "# \$2 ----------------------->  $2       "
    echo "# path to me --------------->  ${0}     " | sed "s/$USER/\$USER/g"
    echo "# parent path -------------->  ${0%/*}  " | sed "s/$USER/\$USER/g"
    echo "# my name ------------------>  ${0##*/} "
    echo
}

Felicidades

linxuser
fonte
1

Curto, claro e simples, em my_script.sh

#!/bin/bash

running_file_name=$(basename "$0")

echo "You are running '$running_file_name' file."

Resultado:

./my_script.sh
You are running 'my_script.sh' file.
Bong Loong A Nhứi
fonte
0

Aqui está o que eu vim com, inspirado por Dimitre Radoulov resposta 's (o que eu upvoted, por sinal) .

script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"

echo "Called $script with $# argument(s)"

independentemente da maneira como você chama seu script

. path/to/script.sh

ou

./path/to/script.sh
Salathiel Genèse
fonte
-1

eco "Você está executando $ 0"

mmacaulay
fonte
Não é script bash, é o caminho completo.
e-info128
-6

algo assim?

export LC_ALL=en_US.UTF-8
#!/bin/bash
#!/bin/sh

#----------------------------------------------------------------------
start_trash(){
ver="htrash.sh v0.0.4"
$TRASH_DIR  # url to trash $MY_USER
$TRASH_SIZE # Show Trash Folder Size

echo "Would you like to empty Trash  [y/n]?"
read ans
if [ $ans = y -o $ans = Y -o $ans = yes -o $ans = Yes -o $ans = YES ]
then
echo "'yes'"
cd $TRASH_DIR && $EMPTY_TRASH
fi
if [ $ans = n -o $ans = N -o $ans = no -o $ans = No -o $ans = NO ]
then
echo "'no'"
fi
 return $TRUE
} 
#-----------------------------------------------------------------------

start_help(){
echo "HELP COMMANDS-----------------------------"
echo "htest www                 open a homepage "
echo "htest trash               empty trash     "
 return $TRUE
} #end Help
#-----------------------------------------------#

homepage=""

return $TRUE
} #end cpdebtemp

# -Case start
# if no command line arg given
# set val to Unknown
if [ -z $1 ]
then
  val="*** Unknown  ***"
elif [ -n $1 ]
then
# otherwise make first arg as val
  val=$1
fi
# use case statement to make decision for rental
case $val in
   "trash") start_trash ;;
   "help") start_help ;;
   "www") firefox $homepage ;;
   *) echo "Sorry, I can not get a $val   for you!";;
esac
# Case stop
hynt
fonte
5
-1, não responde à pergunta (não mostra como encontrar o nome do script) e é um exemplo confuso em um script muito incorreto.
precisa saber é o seguinte