fornecimento de um script Bash - Return on Error, em vez de Exit?

15

Estou adquirindo um script bash no terminal , então, saindo por erro com

set -o errexit

mata meu terminal, o que é extremamente irritante, porque tenho que fechar o terminal, abrir outro e redefinir algumas variáveis.

Até agora, usando

command || return

linhas, no script, está fazendo exatamente o que eu quero

set -o errexit

fazer ... Mas eu quero que seja feito para todo o script; não apenas uma linha / comando

Eu tenho um arquivo cheio de comandos para configurar um site e prefiro não executar o comando || Retorna

para cada linha do arquivo

Existe outra opção definida, ou outra coisa que apenas "retornará" em vez de sair do terminal?

- Para maior clareza , eu gostaria de matar o script e deixar o terminal no mesmo estado que pressionar ctrl + C para matar um serviço em execução no terminal. command || returnfaz isso. Mas não quero aderir || returna todas as linhas do arquivo. Então, estou procurando algo semelhante set -o errexit, que não faça com que o terminal seja desligado

--- Nota: Criando um script burro com duas linhas (super.sh):

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

E colocando set -o errexitno topo do create.sh,

funciona exatamente como eu esperava. No entanto, é realmente estúpido ter que criar um arquivo com duas linhas, apenas para chamar outro script bash, em vez de apenas chamá-lo do terminal. Ugghhh

Aqui estão alguns exemplos:

em super.sh

#!/bin/bash

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

no create.sh

#!/bin/bash
set -o errexit
#line below this is a line that fails and will cause the script to stop and return to the terminal as expected 
sed "s/@@SITE_NAME@@/$dirname" 
~/Desktop/site_builder/template_files/base.html > ~/Desktop/$dirname/templates/base.html # a line with a stupid error

no terminal:

 $ bash super.sh

saída conforme o esperado:

my-mac$

Isso funciona. Que solução irritante.

Eu quero , de preferência, para executar o que está no arquivo super.sh estúpido do terminal, não o arquivo super.sh: D, sem ter o fechamento do terminal para baixo em mim. É o que acontece com o que estou tentando fazer:

comando terminal:

my-mac$ source $create_path blah

no create.sh eu ainda tenho set -o errexit

Aqui está a saída no terminal

    sed: 1: "s/@@SITE_NAME@@/blah": unterminated substitute in regular expression
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[Process completed]

E então o terminal é congelado. Ctrl + C não funciona, nem Ctrl + D

Se, em vez de set -o errexit, se eu apenas usar command || returninstruções em qualquer lugar do arquivo create.sh, obtenho exatamente o que quero, enquanto executo as linhas no supser.sh diretamente no terminal (em vez de chamar super.sh do terminal). Mas essa também não é uma solução prática.

Nota: Gostei da resposta de @terdon sobre gerar um shell filho, então acabei gerando um sub shell por meio do script em vez do terminal, como ele mostrou em sua resposta usando o aparelho ( ), em todo o script .. Sua resposta funciona também


fonte
Você está fazendo isso em um script ou manualmente?
terdon
Estou chamando o arquivo com a fonte no terminal. Como em: source $file_path argumentO script está sendo executado no mesmo shell que eu chamei de (o que sourcefaz, me disseram ... e age como esse) as command || returninstruções estão no arquivo que estou executando no terminal
OK, e onde o conjunto é executado? Isso está no script de origem ou você o executa manualmente? Seria muito mais fácil responder se você pudesse adicionar um exemplo simples que podemos copiar e experimentar. Tenho uma ideia, mas preciso de uma maneira de testar para garantir que funcione.
terdon
Adicionei uma nota à postagem original que pode ajudar com isso. Mas também farei o que você sugeriu.

Respostas:

4

Simplesmente origine o arquivo com segurança:

source the-source-file || true

... então o comando geral não falhará, mesmo que sourceisso aconteça.

Jeff Schaller
fonte
Na verdade, eu pensei que era isso que eu queria, mas acontece que meu terminal estava apenas lento ... Na verdade, eu quero retornar ao terminal por erro (significa parar o script inteiro em suas trilhas) ... por qualquer motivo, source file || true não faz isso, também não source file || return quando eu digito esta no terminal ...
A origem do arquivo não retorna a um prompt de shell?
Jeff Schaller
é isso que está no meu terminal: Jills-MBP:~ jillr$ source ~/Desktop/site_builder/create.sh blah || trueele simplesmente executa a próxima parte do script em falha, assim como retorna em vez de verdadeiro. A única coisa que funcionou são as command || returninstruções no arquivo real para todos os comandos, o que é bobo. Eu não sei se jogar tudo em uma função, em seguida, chamar function || returnno final do arquivo seria bom também.
Bem, se você colocar explicitamente || returnum comando que falhar, o sim retornará. Eu pensei que estávamos tentando impedir que seu shell principal / principal saísse?
Jeff Schaller
Sim, quero impedir que o terminal realmente saia. Porque eu não quero sair do terminal. Eu quero sair do script. O retorno de comandos individuais no script sai do script e deixa meu terminal na mesma condição que pressionar Ctrl + C para interromper um processo, como executar o servidor do terminal. Eu quero evitar escrever o comando || retorne para todas as linhas do arquivo: D
2

Essa é a única coisa que funciona para o que eu precisava realizar (criar um ambiente virtual, ativá-lo e instalar requisitos a partir de um script bash):

gera um shell subshell / filho do script, como em:

stupid_file.sh

(
set -o errexit
#bunch of commands
#one line fails
)

execute o stupid_file usando:

source stupid_file.sh <file arguments here> || true

O FIM.

** faz uma reverência **

(o crédito é para Jeff e Terdon)


fonte
1
Isso não é realmente diferente do que apenas executar o script em vez de fornecê-lo.
chepner
@chepner hmmm. Legal. Vou ter que tentar ligar apenas para bash $create_path blahver se ele ainda existe, e é executado da mesma maneira, e ainda instala coisas no meu ambiente virtual corretamente. Fora de tempo agora.
Economizarei o seu tempo: não será (se "instala coisas" você definir variáveis ​​de ambiente em seu shell atual), nem o fará (...), pois todas as atribuições entre parênteses afetam apenas esse subshell. foo=3; (foo=5); echo "$foo"saída de vontade 3, não 5.
chepner
@chepner não exatamente. Não posso ligar source filedo terminal e esperar os mesmos resultados. Porque isso nunca funcionou. A única vez que obtenho os mesmos resultados é quando crio um sub shell explicitamente, seja pelo terminal ou pelo script. No entanto eu posso usar bashem vez de sourceexecutar o script, e obter os mesmos resultados, mas só quando eu executar o meu script em um sub shell explicitamente
@chepner por instalar coisas, na verdade quero dizer criar um ambiente virtual, ativar esse ambiente virtual e, em seguida, executar pip install -r $apath/requirements.txtdentro desse ambiente ativado. É por isso que usei o source em primeiro lugar para chamar o script
0

Como uma solução alternativa simples, você pode executar um shell no seu shell atual e fonte lá. Algo como:

  1. Abra um novo terminal e configure tudo da maneira que desejar. Você mencionou algumas variáveis ​​de ambiente e similares. Coloque-os aqui.

  2. Nesse terminal, inicie um novo shell. Por exemplo bash,.

  3. Faça a sua coisa. Crie seu script. Se sair, você é jogado no primeiro shell e tudo ainda está configurado. Apenas corra bashnovamente e você estará de volta aos negócios.

Para ilustrar, eu criei este script que falhará se você tentar fonte:

$ cat /home/terdon/scripts/bar.sh
set -o errexit
var='bar

Vamos ver o que acontece se eu iniciar uma sessão de shell aninhado e, em seguida, fonte ele (note que eu estou usando o nome portátil para o sourcecomando .; sourceé um Bashismo):

parent-shell $ bash      ## start a new shell
child-shell $ . ~/scripts/bar.sh
bash: /home/terdon/scripts/bar.sh: line 2: unexpected EOF while looking for matching `''
parent-shell $ 

Como você pode ver, o erro de sintaxe fez com que o script de origem fosse encerrado, o que, por sua vez, causou a saída da minha sessão do shell, mas como era uma sessão aninhada, acabou de me levar de volta ao shell pai original com todas as variáveis ​​ainda configuradas . Agora, basta executar um novo shell novamente e você pode voltar ao fornecimento do seu script.

terdon
fonte
Eu vou tentar isso muito rápido #
Isso tem o efeito pretendido ... a desvantagem é que as variáveis ​​que eu criei para o shell pai não estão acessíveis no shell filho, que contém uma das variáveis ​​necessárias para execução no shell filho. Existe uma maneira de gerar um subshell do arquivo que estou executando? Dessa forma, ainda posso chamar o script no shell pai e ainda posso acessar as variáveis ​​que preciso? Estou literalmente configurando create_path=~/Desktop/site_builder/create.sh o shell pai porque faço isso com frequência. E eu preciso chamar source $ create_path [argument] para executar o script.
1
@JillRussek se as variáveis ​​não estiverem sendo passadas para o shell filho, você não exportas estará usando . Mas o que você descreve realmente faz muito pouco sentido. Parece cada vez mais um problema XY . Você pode postar uma nova pergunta explicando qual é seu objetivo final. Aposto que podemos lhe dar uma solução melhor que toda essa fonte estranha.
terdon
Hmm. Eu também poderia tentar. No momento, apenas gerar o shell filho do script em vez do terminal está fazendo exatamente o que eu quero. Eu tenho que fonte o script do terminal, a fim de criar um ambiente virtual no script, e pip instalar coisas nele. Está funcionando como pretendido agora.
Mas você está certo, eu não estava exportando as variáveis, porque não sabia que precisava: D. (Eu nunca gerou uma concha criança antes)