Como chamar um shell script de outro shell script?

739

Eu tenho dois scripts de shell a.she b.sh.

Como posso chamar b.shde dentro do script de shell a.sh?

Praveen
fonte
8
Você pode dar alguns detalhes: qual sistema operacional e qual shell (s) ou você está apenas falando sobre esse problema em princípio? Um código de exemplo também seria útil.
jsalonen
14
Esta não é realmente uma pergunta específica nem demonstra um esforço prévio para resolver o problema.
Kris
1
Um problema que eu estava tendo era que b.shnão tinha permissões executáveis. Pode ser uma boa coisa para verificar.
seth10
Anexar ./antes do nome do script, por exemplo: em vez disso b.sh, use:./b.sh
Benny
1
Se alguém continua recebendo No such file or directoryerro stackoverflow.com/a/2920431/1356559
Amr Lotfy

Respostas:

959

Existem algumas maneiras diferentes de fazer isso:

  1. Torne o outro script executável, adicione a #!/bin/bashlinha na parte superior e o caminho em que o arquivo está para a variável de ambiente $ PATH. Então você pode chamá-lo como um comando normal;

  2. Ou chame-o com o sourcecomando (alias is .) assim source /path/to/script:;

  3. Ou use o bashcomando para executá-lo: /bin/bash /path/to/script;

Os primeiro e terceiro métodos executam o script como outro processo, portanto, variáveis ​​e funções no outro script não estarão acessíveis.
O segundo método executa o script no processo do primeiro script e extrai variáveis ​​e funções do outro script para que possam ser utilizadas no script de chamada.

No segundo método, se você estiver usando exitno segundo script, ele sairá do primeiro script também. O que não acontecerá no primeiro e no terceiro método.

Algum programador
fonte
30
lembre-se, chmod a+x /path/to/fileou então não será executável. Aplica-se apenas ao método ./script.
Nathan Lilienthal
3
Lembre-se de formato de mudança / codificação de arquivos executáveis em UNIX se eles são criados em DOS e, em seguida, enviado para o ambiente UNIX -> dos2unix <nome do script>
Abhishek Chatterjee
3
@cecemel A primeira e a terceira maneira podem ser "assíncronas" usando a sintaxe normal de execução em segundo plano.
Algum programador cara
16
O problema sourceé que uma exitdeclaração no script chamado também sairá da sua ...
Ohad Schneider
18
@ user528025 .não é um alias para source, mas o contrário. sourceé uma extensão bash, enquanto .trabalha em qualquer shell compatível com POSIX.
Score_Under
207

Veja isso.

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."
Budha
fonte
4
Isso pressupõe que script.sh esteja no mesmo diretório que o script que está sendo executado. Se você quisesse chamar um script para outro lugar, você diriash <path to script>/script.sh
Morgan Kenyon
32
Isso também usa duas conchas bashe sh. Mesmo quando shé de fato bash, não se comporta da mesma maneira. Se você estiver usando #!/bin/bash, provavelmente desejará usar bash script.sh(ou apenas ./script.shusar o hashbang desse script).
Martin Tournoij 14/11
1
Mantive o erro de permissão negada, mesmo quando defino o chmod +xarquivo .sh. Alguma sugestão?
Isaac weathers
@isaacweathers try chmod 777
Janac Meena
114

Existem algumas maneiras de fazer isso. Terminal para executar o script:

#!/bin/bash
SCRIPT_PATH="/path/to/script.sh"

# Here you execute your script
"$SCRIPT_PATH"

# or
. "$SCRIPT_PATH"

# or
source "$SCRIPT_PATH"

# or
bash "$SCRIPT_PATH"

# or
eval '"$SCRIPT_PATH"'

# or
OUTPUT=$("$SCRIPT_PATH")
echo $OUTPUT

# or
OUTPUT=`"$SCRIPT_PATH"`
echo $OUTPUT

# or
("$SCRIPT_PATH")

# or
(exec "$SCRIPT_PATH")

Tudo isso está correto para o caminho com espaços !!!

Andrei Krasutski
fonte
41
Quais são as diferenças deles? Por que um, por que outro?
rocketspacer
. "$ SCRIPT_PATH" é o preferido
Harry Mumford-Turner
1
Posso apenas acrescentar que nem todos são equivalentes, por exemplo, sh "$ SCRIPT_PATH" e bash "$ SCRIPT_PATH" não executam o script #! / Usr / bin / expect, enquanto apenas "$ SCRIPT_PATH" o executará.
Tahlor 23/01/19
58

A resposta que eu estava procurando:

( exec "path/to/script" )

Como mencionado, execsubstitui o shell sem criar um novo processo. No entanto , podemos colocá-lo em um subshell, o que é feito usando os parênteses.

EDIT: Na verdade, ( "path/to/script" )é suficiente.

Maxim Chetrusca
fonte
11
Isso parece bastante complicado. Por que não chamar apenas isso /path/to/script? Eu não vejo a necessidade de exectudo aqui?
Martin Tournoij 14/11/16
O subshell também não é necessário, pois você não está execusando.
Karel Vlk
6
como você executaria esse script com argumentos?
precisa
Se você ainda deseja capturar a saída do sub-script, tente $ (source "path / to / script")
cmcginty
@Bhargav siga este link stackoverflow.com/questions/14302389/…
tpbafk
16

Depende de. Resumidamente ... Se você deseja carregar variáveis ​​no console atual e executar, você pode usar source myshellfile.shno seu código. Exemplo:

!#/bin/bash
set -x
echo "This is an example of run another INTO this session."
source my_lib_of_variables_and_functions.sh
echo "The function internal_function() is defined into my lib."
returned_value=internal_function()
echo $this_is_an_internal_variable

set +x

Se você deseja apenas executar um arquivo e a única coisa interessante para você é o resultado, você pode:

!#/bin/bash
set -x
./executing_only.sh
sh i_can_execute_this_way_too.sh
bash or_this_way.sh
set +x

Espero que ajude você. Obrigado.

Douglas Bonafé
fonte
2
Observe que esse sourceé um recurso específico do bash. A casca de bourne padrão possui apenas .(por exemplo . other_script.sh).
Martin Tournoij 14/11/16
15

Você pode usar /bin/shpara chamar ou executar outro script (via seu script real):

 # cat showdate.sh
 #!/bin/bash
 echo "Date is: `date`"

 # cat mainscript.sh
 #!/bin/bash
 echo "You are login as: `whoami`"
 echo "`/bin/sh ./showdate.sh`" # exact path for the script file

A saída seria:

 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013
Ranjithkumar T
fonte
1
Certamente isso será executado showdate.shem / bin / sh em vez de / bin / bash?
Chris Watts
Eu tentei com " /bin/sh ./showdate.sh", " /bin/bash ./showdate.sh", " ./showdate.sh" e execute o arquivo: mainscript.sh e obtive a mesma saída.
Ranjithkumar T
10

Basta adicionar em uma linha o que você digitou em um terminal para executar o script!
por exemplo:

#!bin/bash
./myscript.sh &

se o script a ser executado não estiver no mesmo diretório, use o caminho completo do script.
por exemplo: `/ home / user / diretório-script /./ myscript.sh &

Anon
fonte
@Carpetsmoker &for background task #
Andrei Krasutski /
9

Primeiro você precisa incluir o arquivo que você chama:

#!/bin/bash
. includes/included_file.sh

então você chama sua função assim:

#!/bin/bash
my_called_function
Ghazi Triki
fonte
9

Fonte simples irá ajudá-lo. Para Ex.

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"
Nitin Jawarkar
fonte
9

Se você tiver outro arquivo no mesmo diretório, poderá:

bash another_script.sh

ou

source another_script.sh

ou

. another_script.sh

Quando você usa, em bashvez de source, o script não pode alterar o ambiente do script pai. O .comando é o padrão POSIX, enquanto o sourcecomando é um sinônimo de bash mais legível para .(eu prefiro sourcesobre .). Se o seu script residir em outro lugar, forneça o caminho para esse script. O caminho relativo e o caminho completo devem funcionar.

Shital Shah
fonte
5

A resposta superior sugere adicionar #!/bin/bashlinha à primeira linha do sub-script que está sendo chamado. Mas mesmo se você adicionar o shebang, é muito mais rápido * executar um script em um sub-shell e capturar a saída:

$(source SCRIPT_NAME)

Isso funciona quando você deseja continuar executando o mesmo intérprete (por exemplo, do bash para outro script do bash) e garante que a linha shebang do sub-script não seja executada.

Por exemplo:

#!/bin/bash
SUB_SCRIPT=$(mktemp)
echo "#!/bin/bash" > $SUB_SCRIPT
echo 'echo $1' >> $SUB_SCRIPT
chmod +x $SUB_SCRIPT
if [[ $1 == "--source" ]]; then
  for X in $(seq 100); do
    MODE=$(source $SUB_SCRIPT "source on")
  done
else
  for X in $(seq 100); do
    MODE=$($SUB_SCRIPT "source off")
  done
fi
echo $MODE
rm $SUB_SCRIPT

Resultado:

~ ❯❯❯ time ./test.sh
source off
./test.sh  0.15s user 0.16s system 87% cpu 0.360 total

~ ❯❯❯ time ./test.sh --source
source on
./test.sh --source  0.05s user 0.06s system 95% cpu 0.114 total

* Por exemplo, quando ferramentas de vírus ou segurança estão sendo executadas em um dispositivo, pode levar mais 100ms para executar um novo processo.

cmcginty
fonte
4
pathToShell="/home/praveen/"   
chmod a+x $pathToShell"myShell.sh"
sh $pathToShell"myShell.sh"
Abdennour TOUMI
fonte
4
 #!/bin/bash

 # Here you define the absolute path of your script

 scriptPath="/home/user/pathScript/"

 # Name of your script

 scriptName="myscript.sh"

 # Here you execute your script

 $scriptPath/$scriptName

 # Result of script execution

 result=$?
Valero
fonte
1
incorreto para pasta scriptPathou nome de arquivo scriptNamecom espaços
Andrei Krasutski
3

Suponha que o novo arquivo seja "/ home / satya / app / app_specific_env" e o conteúdo do arquivo seja o seguinte

#!bin/bash

export FAV_NUMBER="2211"

Anexe esta referência de arquivo ao arquivo ~ / .bashrc

source /home/satya/app/app_specific_env

Sempre que você reiniciar a máquina ou conectar-se novamente, tente echo $FAV_NUMBERno terminal. Isso produzirá o valor.

Apenas no caso, se você quiser ver o efeito imediatamente, source ~/.bashrcna linha de comando.

Satya Kalluri
fonte
3
chmod a+x /path/to/file-to-be-executed

Essa era a única coisa que eu precisava. Depois que o script a ser executado for executável dessa maneira, você (pelo menos no meu caso) não precisará de nenhuma outra operação extra, como shou./ enquanto estiver chamando o script.

Graças ao comentário de @Nathan Lilienthal

Asqan
fonte
1

Existem alguns problemas para importar funções de outro arquivo.
Primeiro : você não precisa executar este arquivo. Melhor não fazer isso! basta adicionar

. file

para importar todas as funções. E todos eles serão como se estivessem definidos no seu arquivo.
Segundo : você pode definir a função com o mesmo nome. Será substituído. É mau. Você pode declarar assim

declare -f new_function_name=old_function_name 

e somente depois disso importamos. Portanto, você pode chamar a função antiga pelo novo nome.
Terceiro : você pode importar apenas a lista completa de funções definidas no arquivo. Se alguns não forem necessários, você pode desmarcá-los. Mas se você reescrever suas funções após a desativação, elas serão perdidas. Mas se você definir a referência conforme descrito acima, poderá restaurar após a definição com o mesmo nome.
FinalmenteNo procedimento comum de importação é perigoso e não é tão simples. Seja cuidadoso! Você pode escrever um script para fazer isso mais fácil e seguro. Se você usar apenas parte das funções (não todas), é melhor dividi-las em arquivos diferentes. Infelizmente, essa técnica não se saiu bem no bash. No python, por exemplo, e em outras linguagens de script, é fácil e seguro. É possível fazer importação parcial apenas das funções necessárias com seus próprios nomes. Todos nós queremos que nas próximas versões do mato seja feita a mesma funcionalidade. Mas agora precisamos escrever muitos bacalhaus adicionais para fazer o que quiser.

Anatoly
fonte
(Bem-vindo ao SO!) Como o usuário Praveen foi visto pela última vez em 2011, é difícil determinar se a questão era como fazer o shell executar a.sh executar b.sh (e continuar executando a.sh, se não ordenou o contrário ), ou literalmente b.sh chamada . (Meu verificador ortográfico não pega bush versions.) (Você tem alguém a quem recorrer para ajudá-lo com a gramática inglesa? (Às vezes gostaria que eu tivesse.)) #
Greybeard
0

Use retalhos.

$ ./script-that-consumes-argument.sh `sh script-that-produces-argument.sh`

Em seguida, busque a saída do script produtor como um argumento no script consumidor.

dacabdi
fonte