Bash 스크립트 소싱-Exit 대신 Error on Return?


17

터미널에서 떠들썩한 파티 스크립트를 소싱 그래서 함께 오류에 종료,

set -o errexit

터미널을 닫고 다른 터미널을 열고 일부 변수를 재설정해야하기 때문에 EXTREMELY ANNOYING 터미널을 죽입니다.

지금까지

command || return

스크립트에서 라인은 내가 원하는 것을 정확하게하고 있습니다.

set -o errexit

해야 할 일 ... 그러나 나는 전체 스크립트를 위해 그것을 원합니다. 한 줄 / 명령이 아니라

사이트를 설정하는 명령으로 가득 찬 파일이 있으며 명령 || 반환

파일의 모든 줄마다

터미널을 종료하는 대신 "복귀"할 다른 설정 옵션 또는 다른 옵션이 있습니까?

- 명확성 을 위해 스크립트를 종료하고 터미널에서 실행되는 서비스를 종료하기 위해 ctrl + C를 누르는 것과 동일한 상태로 터미널을 유지하고 싶습니다. command || return것을 수행. 그러나 || return파일의 모든 줄에 고정하고 싶지 않습니다 . 그래서 set -o errexit터미널을 종료시키지 않는 비슷한 것을 찾고 있습니다.

--- 참고 : 두 줄이 포함 된 바보 스크립트 만들기 (super.sh) :

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

set -o errexitcreate.sh의 맨 위에 배치 하면

내가 예상대로 정확하게 작동합니다. 그러나 터미널에서 파일을 호출하는 대신 다른 bash 스크립트를 호출하기 위해 두 줄로 파일을 작성하는 것은 정말 어리 석습니다. 어 gg

다음은 몇 가지 예입니다.

super.sh에서

#!/bin/bash

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

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

터미널에서 :

 $ bash super.sh

예상대로 출력 :

my-mac$

작동합니다. 정말 귀찮은 해결책입니다.

내가 원하는 날 아래 터미널 종료를하지 않고, D : 이상적으로, 터미널이 아닌 super.sh 파일에서 바보 super.sh 파일에 무엇이 실행. 이것은 내가하려는 일에서 일어나는 일입니다.

터미널 명령 :

my-mac$ source $create_path blah

create.sh에서 나는 여전히 set -o errexit

다음은 터미널의 출력입니다

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

[Process completed]

그런 다음 터미널이 고정됩니다. Ctrl + C가 작동하지 않으며 Ctrl + D도 작동하지 않습니다

대신 create.sh 파일의 모든 곳에서 명령문을 set -o errexit사용 command || return하면 터미널에서 직접 supser.sh의 행을 실행하는 동안 터미널에서 supser.sh의 행을 실행하는 동안 원하는 것을 정확하게 얻을 수 있습니다. 그러나 그것은 실제적인 해결책이 아닙니다.

참고 : 나는 자식 쉘을 생성하는 것에 대한 @terdon의 대답을 좋아했기 때문에 터미널 대신 스크립트를 통해 하위 쉘을 생성하는 것을 끝내 었습니다. 그는 ( )전체 스크립트 주위에 중괄호를 사용하여 자신의 답변에 표시했습니다 . 작동합니다.


스크립트 나 수동으로이 작업을 수행하고 있습니까?
terdon

터미널에서 소스를 사용하여 파일을 호출하고 있습니다. 에서와 같이 : source $file_path argument스크립트는 내가 호출 한 것과 동일한 쉘에서 실행되고 있습니다 (무엇을 source들었 command || return

좋아, 세트는 어디에서 실행됩니까? 소스 스크립트에 있습니까? 아니면 수동으로 실행합니까? 복사하여 사용해 볼 수있는 간단한 예를 추가 할 수 있다면 대답하기가 훨씬 쉬울 것입니다. 아이디어가 있지만 작동하는지 테스트하는 방법이 필요합니다.
terdon

원래 게시물에 도움이 될 수있는 메모를 추가했습니다. 그러나 나는 당신이 제안한대로 할 것입니다.

답변:


5

파일을 안전 장치로 간단히 소싱하십시오.

source the-source-file || true

... 그렇더라도 전반적인 명령은 실패 source하지 않습니다.


사실, 나는 이것이 내가 원하는 것이라고 생각했지만 터미널이 느리다는 것을 알았습니다 ... 실제로 터미널로 돌아가고 싶습니다 (트랙에서 전체 스크립트를 중지한다는 의미). source file || true 이 작업을 수행하지 않거나 source file || return 터미널에 입력 할 때도 수행하지 않습니다 .

파일을 소싱해도 쉘 프롬프트로 돌아 가지 않습니까 ??
Jeff Schaller

이것은 내 터미널에있는 것입니다 : Jills-MBP:~ jillr$ source ~/Desktop/site_builder/create.sh blah || true그것은 실패했을 때 단순히 스크립트의 다음 부분을 실행하므로 true 대신에 반환합니다. 작동 한 유일한 것은 command || return모든 명령에 대한 실제 파일의 명령문입니다. 함수에서 모든 것을 던지면 function || return파일 끝에서 호출 하면 어느 것도 잘 될 것입니다.

글쎄, || return실패한 명령을 명시 적으로 넣으면 예, 반환됩니다. 나는 우리가 당신의 주 / 부모 껍질을 끝내려고 노력하고 있다고 생각 했습니까?
Jeff Schaller

예, 터미널이 실제로 종료되는 것을 막고 싶습니다. 터미널을 종료하고 싶지 않기 때문입니다. 스크립트를 종료하고 싶습니다. 스크립트에서 개별 명령에 대한 리턴은 스크립트를 종료하고 터미널에서 서버 실행과 같은 프로세스를 종료하기 위해 Ctrl + C를 누르는 것과 같은 조건으로 터미널을 그대로 둡니다. 명령 작성을 피하고 싶습니다 || 파일의 모든 줄에 대해 반환 : D

3

이것이 내가 달성해야 할 유일한 일입니다 (가상 환경을 생성하고 활성화 한 다음 bash 스크립트에서 요구 사항 설치).

다음과 같이 스크립트에서 서브 쉘 / 자식 쉘을 생성합니다 :

stupid_file.sh

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

다음을 사용하여 stupid_file을 실행하십시오.

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

끝.

** 활을 가지고 **

(신용은 Jeff와 Terdon에게갑니다)


1
이것은 단지 스크립트를 소싱하는 대신 단순히 실행하는 것과 다르지 않습니다.
chepner

@chepner hmmm. 멋있는. 그냥 전화를 bash $create_path blah걸어서 여전히 종료하고 동일한 방식으로 실행되는지 확인하고 가상 환경에 물건을 올바르게 설치해야합니다. 시간이 없어

시간을 절약 할 수 있습니다. (...)괄호 안의 모든 할당은 해당 서브 쉘에만 영향을주기 때문에 "설치를한다면"현재 셸에서 환경 변수를 설정한다는 의미입니다 . foo=3; (foo=5); echo "$foo"5가 아닌 3을 출력합니다.
chepner

@chepner는 정확하지 않습니다. source file터미널에서 전화 를 걸 수 없으며 동일한 결과를 기대합니다. 그것은 결코 효과가 없었기 때문입니다. 동일한 결과를 얻을 수있는 유일한 시간은 터미널을 통해 또는 스크립트에서 하위 셸을 명시 적으로 만들 때입니다. 그러나 스크립트를 실행하는 bash대신 대신 source동일한 결과를 얻을 수 있지만 서브 쉘에서 스크립트를 명시 적으로 실행할 때만

@chepner를 설치하면 실제로 가상 환경을 만들고 해당 가상 환경을 활성화 한 다음 pip install -r $apath/requirements.txt활성화 된 환경 내에서 실행 합니다. 그래서 소스를 사용하여 스크립트를 호출했습니다.

1

간단한 해결 방법으로 현재 쉘에서 쉘을 실행하여 소스를 얻을 수 있습니다. 다음과 같은 것 :

  1. 새 터미널을 열고 원하는 방식으로 모든 것을 설정하십시오. 환경 변수 등을 언급했습니다. 여기에 설정하십시오.

  2. 해당 터미널에서 새 쉘을 시작하십시오. 예를 들어 bash.

  3. 당신의 일을하십시오. 스크립트를 소싱하십시오. 종료되면 첫 번째 쉘에 던져지고 모든 것이 여전히 설정됩니다. bash다시 실행 하면 다시 사업을 시작합니다.

예를 들어,이 스크립트를 작성했는데 소스를 작성하려고하면 실패합니다.

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

중첩 된 셸 세션을 시작한 다음이를 소싱하면 어떻게되는지 봅시다 ( source명령에 휴대용 이름을 사용하고 있습니다 .; sourcebashism입니다).

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 $ 

보시다시피, 구문 오류로 인해 소스 스크립트가 종료되었습니다. 이로 인해 쉘 세션이 종료되었지만 중첩 세션이므로 모든 변수가 설정된 원래의 상위 쉘로 다시 돌아 왔습니다. . 이제 새 쉘을 다시 실행하면 스크립트 소싱으로 돌아갈 수 있습니다.


나는 이것을 정말로 빨리 시도 할 것이다

이것은 의도 한 효과가 있습니다 ... 단점은 부모 셸에 대해 생성 한 변수가 자식 셸에서 액세스 할 수 없으며 자식 셸에서 실행하는 데 필요한 변수 중 하나가 포함되어 있다는 것입니다. 내가 실행중인 파일에서 서브 쉘을 생성하는 방법이 있습니까? 그렇게하면 여전히 부모 쉘에서 스크립트를 호출 할 수 있으며 필요한 변수에 계속 액세스 할 수 있습니까? 나는 create_path=~/Desktop/site_builder/create.sh 종종 그렇게하기 때문에 문자 그대로 부모 쉘에서 설정 하고 있습니다. 스크립트를 실행하려면 소스 $ create_path [argument]를 호출해야합니다.

1
@JillRussek 변수가 자식 쉘에 전달되지 않으면 변수가 없습니다 export. 그러나 당신이 묘사하는 것은 실제로 거의 이해가되지 않습니다. 점점 더 XY 문제 처럼 들린다 . 최종 목표가 무엇인지 설명하는 새로운 질문을 게시 할 수 있습니다. 이 모든 이상한 소싱에 대해 더 나은 솔루션을 제공 할 수 있습니다.
terdon

흠. 나도 그 기회를 줄 수 있습니다. 지금은 터미널 대신 스크립트에서 자식 셸을 스폰하는 것이 내가 원하는 일을 정확하게 수행하는 것입니다. 스크립트에서 가상 환경을 만들고 pip 설치 항목을 작성하려면 터미널에서 스크립트를 소싱해야합니다. 의도 한대로 작동합니다.

그러나 당신이 옳습니다. 변수를 내 보내지 않았습니다. (저는 이전에 자식 셸을 생성 한 적이 없습니다)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.