쉘 언어

쉘 언어

긴 이야기 짧게

나는 이것에 대해 몇 가지 조사를 했고 당신은 내가 한 일을 볼 수 있습니다더 자세한 내용과 나의 시도부분.

내 명령은

date && echo "hi 1" && echo "1/0" | bc >/dev/null 2>&1 && echo "hi 2" && date +'%s'

내 예상/원하는 출력은 다음과 같습니다.

Tue, Nov 17, 2020  3:13:49 PM
hi 1

그리고 멈추게 하세요. 내 생각은 표현식의 " echo/ bc" 부분입니다 (작업 우선 순위가 괄호로 표시된다고 가정)

<part-before> ( echo "1/0" | bc >/dev/null 2>&1 ) && <part-after>

<part-after>목적이 달성되지 않도록 해야 합니다 . 그러나 내실제출력( date현재 명령 사용)은 다음과 같습니다.

Tue, Nov 17, 2020  3:13:49 PM
hi 1
hi 2
1605651229

질문: 아무것도 출력하지 않고 실패하고 0으로 나누기 문제에서 멈추게 하려면 어떻게 해야 합니까?


(이후의 내용은 더 자세한 내용을 제공하기 위한 것입니다.)

빠른 참고 사항: 리디렉션이 없더라도 0으로 나누는 데 실패해도 체인 &&, 즉 단락된 AND 연산자 체인이 중지되지 않습니다. 보다,

bballdave025@MACHINE ~
$ date && echo "hi 1" && echo "1/0" | bc && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:14:47 PM
hi 1
Runtime error (func=(main), adr=3): Divide by zero
hi 2
1605651287

bballdave025@MACHINE ~
$

bc나는 주로 $(( ))아래와 같은 bash-ism을 피하기 위해 이 방법을 사용하고 싶습니다 . (bash-isms에 대해 말하자면, 노력해도 &>/dev/null아무 것도 바뀌지 않았습니다.) 아래 예와 같은 것을 얻고 싶습니다.

bballdave025@MACHINE ~
$ date && echo "hi 1" && echo "$((1/0))" >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:15:17 PM
hi 1
-bash: 1/0: division by 0 (error token is "0")

bballdave025@MACHINE ~
$

하지만 나는 오류를 원하지 않습니다. 0으로 나눈 잘못된 결과가 출력되지 않는 한, 즉 -ed가 없으면 echo오류를 제거할 수 있습니다 (이는 리디렉션의 목적을 무너뜨리고stdoutstderr

### NOT WHAT I WANT, other than what is output ###
bballdave025@MACHINE ~
$ date && echo "hi 1" && ((1/0)) >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:15:44 PM
hi 1

bballdave025@MACHINE ~
### NOT WHAT I WANT, other than what is output. ###

좀 더 이론적인 설명은 다음과 같습니다.무엇에 0(영)을 전달하고 있습니다 &&. 무엇입니까?

나는 발견했다이 소스(보관됨), 즉

리디렉션은 명령이 아닙니다.

지금은 어디를 봐야할지 모르겠습니다.


편집하다: 좀 더 조사해 봤습니다. 두 가지 점을 추가하고 싶습니다.

  1. 여러 소스를 찾았습니다.그들 중 하나(보관됨) 이것이 핵심일 수 있다고 생각하지만 그것이 어떻게 적용되는지 여전히 이해하지 못합니다.다른(보관됨) 단락에 대해 설명하는데, 이것이 중요할 수 있다고 생각됩니다.

  2. >/dev/null실수로 로 교체했을 때 이상한 동작을 발견하여 >dev/null버그가 발생했습니다.뒤쪽에문제를 0으로 나눕니다. 이것이 내가 보는 것입니다.

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:41:39 PM
hi 1
-bash: dev/null: No such file or directory

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:41:48 PM
hi 1
-bash: dev/null: No such file or directory

bballdave025@MACHINE ~
$

솔직히 이것은 특히 첫 번째, 아마도 핵심 소스를 고려하면 더욱 혼란스럽습니다.


더 자세한 내용과 나의 시도

나는 더 큰 실행 파일을 포함하는 더 긴 체인을 구축하기 위해 &&체인과 리디렉션을 이해하려고 노력하고 있습니다. /dev/null나도 알고 싶다명령 목록 구분 기호(보관됨) 일반적으로 말하면 이러한 실행 파일이 어떻게 함께 작동하는지에 관계없이 여기서 무슨 일이 일어나고 있는지 정말로 이해하고 싶습니다 &&.

나는 실제 예제로 넘어가기 전에 이 장난감 예제를 작업해 왔습니다. 나는 문제를 찾을 수 있는지 확인하기 위해 "뒤로 작업"하려고 노력해 왔습니다. 아마도 이것은 문제를 해결하는 데 유용할 것입니다.

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:16:41 PM
hi 1
hi 2
1605651401

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:16:52 PM
hi 1
hi 2
1605651412

## LET'S SEE WHAT GETS SENT TO /dev/null

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:17:06 PM
hi 1
hi 2
1605651426

bballdave025@MACHINE ~
$ cat abc
1

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:17:18 PM
hi 1
hi 2
1605651438

bballdave025@MACHINE ~
$ cat abc
Runtime error (func=(main), adr=3): Divide by zero

## LET'S TRY GIVING IT ANOTHER ERROR RIGHT AFTER

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:24:35 PM
hi 1
-bash: dev/null: No such file or directory

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:00 PM
hi 1
-bash: dev/null: No such file or directory

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:14 PM
hi 1
hi 2
1605651914

bballdave025@MACHINE ~
$ cat abc
1

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:24 PM
hi 1
hi 2
1605651924

bballdave025@MACHINE ~
$ cat abc
Runtime error (func=(main), adr=3): Divide by zero

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >abc/def 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:41 PM
hi 1
-bash: abc/def: Not a directory

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >abc/def 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:46 PM
hi 1
-bash: abc/def: Not a directory

## GO BACK WITHOUT `bc` and without redirection

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:29:03 PM
hi 1
hi 2
1605652143

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:29:12 PM
hi 1
hi 2
1605652152

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:29:21 PM
hi 1
hi 2
1605652161

bballdave025@MACHINE ~
$ cat abc
1/1

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:29:29 PM
hi 1
hi 2
1605652169

bballdave025@MACHINE ~
$ cat abc
1/0

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:30:09 PM
hi 1
1/1
hi 2
1605652209

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:30:14 PM
hi 1
1/0
hi 2
1605652214

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:30:26 PM
hi 1
hi 2
1605652226

bballdave025@MACHINE ~
$

이 SO 교환(보관됨) 유용한 것이 있을 수 있습니다.

답변1

리디렉션이 없더라도 0으로 나누는 데 실패하더라도 "and" 연산자의 단락 체인인 && 체인이 중지되지 않습니다.

GNU BC:

$ echo "1/0" | bc 
Runtime error (func=(main), adr=3): Divide by zero
$ echo $?
0

바쁜 상자:

$ echo "1/0" | busybox bc 
bc: divide by zero
$ echo $?
1

POSIX BC:

이름
bc - 임의 정밀도 산술 언어
종료 상태
다음 종료 값이 반환되어야 합니다.
0 - 모든 입력 파일이 성공적으로 처리되었습니다.
지정되지 않음 - 오류가 발생했습니다.

근거
오류 조건의 종료 상태는 여러 가지 이유로 지정되지 않습니다.

  • bc 유틸리티는 대화형 상황과 비대화형 상황 모두에서 사용할 수 있습니다. 두 가지 목적 모두에 서로 다른 종료 코드가 적합할 수 있습니다.
  • 0이 아닌 종료가 언제 제공되어야 하는지는 명확하지 않습니다. 0으로 나누기, 정의되지 않은 함수 및 구문 오류가 모두 가능합니다.
  • 종료 상태가 어떤 용도로 사용되는지는 확실하지 않습니다.

BC는 0으로 나누는 것이 잘못된 종료 상태를 반환할 가치가 없다고 생각하기 때문에 체인이 끊어지지 않습니다.

그러나 GNU bc는 입력 파일을 읽을 수 없는 경우 잘못된 종료 상태를 반환합니다.

나는 주로 나중에 $(( ))와 같은 bash-isms를 피하기 위해 bc 방법을 사용하고 싶습니다.

$(( ))바시즘이 아니라 바시즘의 일부POSIX 쉘 언어(산술 확장).


&&여기서의 맥락이 무엇인지, 0으로 나누는 것이 조건 및 체인과 어떻게 관련되는지, 궁극적으로 무엇을 하려는지 잘 모르므 로 조언을 제공하기가 어렵습니다.

0으로 나누기를 감지하는 또 다른 방법은 나누기를 먼저 시도하기 전에 나누기가 0인지 확인하는 것입니다.

답변2

이는 XY 문제, 파이프, 출력 및 분할 문제가 혼합된 것입니다. 답변해야 할 "단일" 질문이 있는 것 같지는 않지만 이를 명확히 하려고 노력할 것입니다.

쉘 언어

그룹

echo "before" && echo inside1 && echo inside2 && echo "after"

여러 명령문을 그룹화하는 방법은 괄호나 중괄호를 사용하는 것입니다.

echo "before" && ( echo inside1 && echo inside2 ) && echo "after"
echo "before" && { echo inside1 && echo inside2; } && echo "after"

()서브쉘에서 실행되며 { }단순히 현재 환경에서 목록을 형성합니다. 둘 다 해당 섹션의 출력을 리디렉션하는 데 사용할 수 있습니다.

echo "before" && ( echo inside1 && echo inside2 ) > /dev/null && echo "after"
echo "before" && { echo inside1 && echo inside2; } > /dev/null && echo "after"

반환 값

각 명령은 완료 후 값을 반환합니다. $?사용하실 수 있도록 저장되어 있습니다.echo $? 실행 직후.

성공을 나타내려면 0을 반환하고 실패를 나타내려면 0이 아닌 값을 반환하는 것이 규칙입니다. 어떤 계획이든 성공으로 간주될 수 있습니다. and &&및 또는 ||쉘 연산자는 이 개념을 활용합니다. 또한 항상 0(성공)과 0이 아닌 값(실패)을 반환하는 trueand 라는 편리한 유틸리티도 있습니다 .false

if true && false; then
 echo Yes
else
 echo No
fi

series 를 연결하면 &&연산자의 오른쪽은 왼쪽이 성공을 반환하는 경우에만 실행됩니다.

photos예를 들어, 이라는 폴더를 만들고 모든 파일을 그 폴더로 이동할 수 있습니다 .

먼저 사용해 볼 수 있습니다.

mv *.jpg photos

그러나 사진이 하나만 있고 photos폴더가 없으면 사진 이름이 로 변경됩니다 photos.

폴더가 성공적으로 생성되면 해당 폴더를 사용하여 이미지를 이동할 수만 있습니다 &&.

mkdir photos && mv *.jpg photos

mkdir실패 하면 mv실행되지 않습니다.

mkdir이는 실패 시 0이 아닌 값이 반환되기 때문입니다 .

그러나 폴더가 photos이미 존재하는 경우 mkdir오류 조건도 반환됩니다(폴더를 만들 수 없습니다).

따라서 더 복잡한 검사는 다음과 같습니다.

( test -d photos || mkdir photos ) && mv *.jpg photos/

photos가 이미 디렉토리인 경우 디렉토리를 생성하려고 시도하지 않고 대신 이미지 이동으로 이동합니다. 그러나 photos디렉터리는 아니지만 생성할 수 있으면 성공하고 사진을 이동합니다.

사진이 폴더(또는 폴더에 대한 심볼릭 링크)가 아니고 생성되지 않은 경우 왼쪽 부분이 &&실패하고 사진이 이동하지 않습니다.

참고 사항: 이 특정 예의 경우 더 간단한 것을 사용할 수 있습니다 mkdir -p photos && mv *.jpg photos/. -p플래그를 사용하면 mkdir이 중간 폴더를 생성하고 폴더가 이미 존재하는 경우 종료되지 않지만 덜 설득력이 있기 때문입니다.

관로

파이프가 있는 경우 기본적으로 파이프의 반환 값은 가장 오른쪽 명령 중 하나입니다. 실행하면

command1 | command2 | command3

전체 파이프라인의 반환 값은 의 반환 값이 됩니다 command3. command1또는 command20이 아닌 값을 반환하는 것은 중요하지 않습니다. pipefail반환 값이 다음 중 하나가 되도록 옵션을 설정하여 이를 변경할 수 있습니다.0이 아닌 값을 반환하는 파이프라인의 가장 오른쪽 명령.

0으로 나누기

귀하의 경우 0으로 나누기 시도에 대한 진단을 화면에 제공하더라도 0 코드가 실제로 반환되기 echo 1/0 | bc때문에 파이프라인이 중지되지 않습니다 .bc

$((1/0))확장 프로그램에서 오류가 발생하기 때문에 직접 실행하는 데 문제가 있습니다. 새로운 셸 프로세스로 래핑할 수 있습니다.

echo hi1 && bash -c 'echo $((1/0))' 2> /dev/null && echo hi2

아니면 그냥 서브쉘일 수도 있어요

echo hi1 && ( echo $((1/0))' ) 2> /dev/null && echo hi2

실제로 기본적인 솔루션이 있습니다.제수가 0인지 확인. 예를 들어:

division() {
  if [ "$2" -eq 0 ]; then
     return 1
  fi
  echo "$(( $1 / $2 ))"
}

echo hi1 && division 1 0 && echo hi2

함수를 사용하여 비슷한 작업을 수행할 수도 있습니다 bc(그러나 아무것도 출력하지 않는 대신 0을 출력합니다).

define division(x,y) {
   if (y == 0) return;
   return x/y;
}
division(1,0)

관련 정보