서브 쉘없이 여러 조건이 없다면 bash?


23

쉘 if 문에서 여러 조건을 결합하고 조합을 무효화하고 싶습니다. 간단한 조건 조합을 위해 다음 작업 코드가 있습니다.

if [ -f file1 ] && [ -f file2 ] && [ -f file3 ] ; then
  # do stuff with the files
fi

이것은 잘 작동합니다. 그것을 부정하고 싶다면 다음 작업 코드를 사용할 수 있습니다.

if ! ( [ -f file1 ] && [ -f file2 ] && [ -f file3 ] ) ; then
  echo "Error: You done goofed."
  exit 1
fi
# do stuff with the files

이것은 예상대로 작동합니다. 그러나 괄호가 실제로 무엇을하는지 모르겠습니다. 내가 원하는 단지 그룹화를 사용하지만 실제로 서브 쉘을 산란한다? (어떻게 알 수 있습니까?) 그렇다면 서브 쉘을 생성하지 않고 조건을 그룹화하는 방법이 있습니까?


부울 논리를 사용하여 동등한 표현을 결정할 수 있다고 가정합니다. if ! [ -f file1 ] || ! [ -f file 2 ] || ! [ -f file3 ] ; then그러나 더 일반적인 대답을 원합니다.
와일드 카드

당신은 예를 들어, 괄호 안에 무효화 수도 있습니다if [[ ! -f file1 ]] && [[ ! -f file2 ]]; then
DopeGhoti

1
예, 방금 테스트 if [ ! 1 -eq 2 ] && [ ! 2 -eq 3 ]; then echo yep; fi했으며 작동합니다. 나는 습관적으로 항상 이중 괄호로 테스트를 작성합니다. 또한 그것이 아닌지 확인하기 위해 bash추가 테스트를 거쳐 if /bin/test ! 1 -eq 2 && /bin/test ! 2 -eq 3 ; then echo yep; fi그 방식으로 작동합니다.
DopeGhoti

1
@Wildcard- [ ! -e file/. ] && [ -r file ]디렉토리를 삭제합니다. 당신이 원하는대로 그것을 부정하십시오. 물론 -d그렇습니다.
mikeserv

1
관련 질문 (유사하지만 많은 토론과 답변이 도움이되지 않음) : unix.stackexchange.com/q/156885/135943
Wildcard

답변:


32

{ list;}대신에 사용해야 합니다 (list):

if ! { [ -f file1 ] && [ -f file2 ] && [ -f file3 ]; }; then
  : do something
fi

둘 다 그룹화 명령 이지만 { list;}현재 쉘 환경에서 명령을 실행합니다.

는 그 주 ;{ list;}에서 목록 구분하기 위해 필요한 }역 단어를, 당신은뿐만 아니라 다른 구분 기호를 사용할 수 있습니다. 이후의 공백 (또는 다른 구분 기호) {도 필요합니다.


고맙습니다! 처음에 나를 트립 한 것 (에서 awk보다 더 자주 중괄호를 사용하기 때문에 bash)은 열린 중괄호 뒤에 공백이 필요합니다. "다른 구분 기호도 사용할 수 있습니다"라고 언급했습니다. 예가 있습니까?
와일드 카드

@Wildcard : 예, 열린 중괄호 뒤에 공백이 필요합니다. 함수를 정의하려는 경우가 많으므로 다른 구분 기호의 예는 줄 바꿈입니다.
cuonglm

@ don_crissti :에서 zsh, 당신은 공백을 사용할 수 있습니다
cuonglm

@ don_crissti : &는 또한 구분 기호이며 { echo 1;:&}, 여러 줄 바꿈을 사용할 수도 있습니다.
cuonglm

2
매뉴얼에서 메타 문자 인용을 사용할 수 있습니다 they must be separated from list by whitespace or another shell metacharacter.. bash에서는 다음과 같습니다 metacharacter: | & ; ( ) < > space tab . 이 특정 작업을 위해 나는 모든 것이 효과 & ; ) space tab가 있다고 생각합니다 . .... .... zsh (의견) : each sublist is terminated by ; ', &', & |',&!', or a newline.

8

원하는 test기능을 전적으로 사용할 수 있습니다 . 의 맨 페이지에서 test:

 ! expression  True if expression is false.
 expression1 -a expression2
               True if both expression1 and expression2 are true.
 expression1 -o expression2
               True if either expression1 or expression2 are true.
 (expression)  True if expression is true.

따라서 상태는 다음과 같습니다.

if [ -f file1 -a -f file2 -a -f file3 ] ; then
    # do stuff with the files
fi

이스케이프 처리 된 괄호를 부정하는 경우 :

if [ ! \( -f file1 -a -f file2 -a -f file3 \) ] ; then
    echo "Error: You done goofed."
    exit 1
fi
# do stuff with the files

6

이식 쉘에서 복잡한 조건을 부정, 당신도 적용해야합니다 드 모건의 법칙 과 안쪽 끝까지 부정을 눌러 [통화 ...

if [ ! -f file1 ] || [ ! -f file2 ] || [ ! -f file3 ]
then
    # do stuff
fi

... 또는 사용해야합니다 then :; else...

if [ -f file1 ] && [ -f file2 ] && [ -f file3 ]
then :
else
  # do stuff
fi

if ! command휴대 할 수 없으며 둘 다 아닙니다 [[.

완전한 이식성이 필요 하지 않다면 쉘 스크립트를 작성하지 마십시오 . 당신은 실제로 당신 보다 무작위로 선택된 유닉스 에서 찾을 가능성 이 큽니다 ./usr/bin/perlbash


1
!요즘 포터블 한 POSIX입니다. Bourne 쉘과 함께 제공되는 시스템도 표준 구문을 해석하는 데 사용할 수있는 POSIX 파일 시스템의 다른 곳에 있습니다.
Stéphane Chazelas

@ StéphaneChazelas 이것은 기술적으로 사실이지만 필자의 경험으로는 POSIX 호환 쉘 환경을 찾아서 활성화하는 번거 로움을 처리하는 것보다 Perl에서 스크립트를 다시 작성하는 것이 더 쉽다 /bin/sh. Autoconf 스크립트는 당신이 제안한대로 수행하지만, 우리 모두가 보증하는 것이 거의 없다는 것을 알고 있다고 생각합니다.
zwol

5

다른 사람들은 {복합 명령 ;}그룹화에 주목 했지만 세트 에서 동일한 테스트를 수행하는 경우 다른 종류를 사용하려고 할 수 있습니다.

if  ! for f in file1 file2 file3
      do  [ -f "$f" ] || ! break
      done
then  : do stuff
fi

... 다른 곳에서 시연되는 것처럼 { :;}복합 명령 중첩과 관련된 어려움은 없습니다 ...

위의 (일반적으로) 일반 파일을 테스트 합니다. 당신은 단지를 찾는 경우에 기존 , 읽을 디렉토리 수없는 파일 :

if  ! for f in file1 file2 file3
      do  [ ! -d "$f" ] && 
          [   -r "$f" ] || ! break
      done
then  : do stuff
fi

디렉토리인지 아닌지 신경 쓰지 않는다면 :

if  ! command <file1 <file2 <file3
then  : do stuff
fi

... 어떤을위한 작품 읽기 , 접근 파일,하지만 가능성이 w 인 / 아웃 작가 FIFO를 위해 중단됩니다.


2

이것은 주요 질문에 대한 완전한 답변은 아니지만 주석에서 복합 테스트 (읽기 가능한 파일)를 언급 한 것으로 나타났습니다. 예를 들어

if [ -f file1 ] && [ -r file1 ] && [ -f file2 ] && [ -r file2 ] && [ -f file3 ] && [ -r file3 ]

쉘 함수를 정의하여 이것을 조금 강화할 수 있습니다. 예를 들어

readable_file()
{
    [ -f "$1" ]  &&  [ -r "$1" ]
}

[ $# = 1 ]맛을 내기 위해 오류 처리를 추가하십시오 (예 :). 위의 첫 번째 if진술은 이제

if readable_file file1  &&  readable_file file2  &&  readable_file file3

함수의 이름을 줄여서 더 단축시킬 수 있습니다. 마찬가지로 함수에 부정을 정의 not_readable_file()(또는 nrf간단히)하고 포함 할 수 있습니다.


좋지만 루프를 추가하지 않는 이유는 무엇입니까? readable_files() { [ $# -eq 0 ] && return 1 ; for file in "$@" ; do [ -f "$file" ] && [ -r "$file" ] || return 1 ; done ; } (면책 조항 :이 코드를 테스트했지만 작동하지만 하나의 라이너가 아닙니다. 여기에 게시 할 세미콜론을 추가했지만 배치를 테스트하지 않았습니다.)
Wildcard

1
좋은 지적. 함수에서 더 많은 제어 (연결) 논리를 숨기고 있다는 사소한 우려를 제기 할 것입니다. 스크립트를 읽어 볼 사람이 if readable_files file1 file2 file3없는 것 알고 함수가 수행되었는지 여부를 ANDOR - 비록 (A) 나는 그것이 매우 직관적 인 것 같아요, (b)는 스크립트를 배포하지 않는 경우 경우, 그것은 좋은 충분 당신이 그것을 이해, 그리고 (c) 함수 이름을 불명확하게 표현할 것을 제안했기 때문에, 나는 가독성에 관해 이야기 할 입장이 없다. … (계속)
G-Man, 'Reinstate Monica'라고

1
(계속)가 ... BTW, 함수는 잘 당신이 그것을 쓴 방법입니다,하지만 당신은 대체 할 수 for file in "$@" ; dofor file do-가 기본값 in "$@"(가)와 (다소 반 직관적) ;만 필요하지만, 실제로는 낙심하지 않습니다.
G-Man은 'Reinstate Monica'라고

0

중괄호 테스트 내에서 무효화하여 원래 코드를 재사용 할 수도 있습니다.

if [[ ! -f file1 ]] || [[ ! -f file2 ]] || [[ ! -f file3 ]] ; then
  # do stuff with the files
fi

2
당신은 필요 ||대신&&
cuonglm

시험은 아니다 "이다 어떤 거기 파일은"시험은 "없는 것도 이 파일의". 사용 ||하는 경우 술어를 실행 할 어떤 파일이 존재하지 않습니다 만 IFF에하지 않을 경우 모든 파일의 존재하지 않습니다. NOT (A AND B AND C)은 (NOT) 및 (NOT B) 및 (NOT C)와 동일합니다. 원래 질문을 참조하십시오.
DopeGhoti

@DopeGhoti, cuonglm이 맞습니다. 그렇지 않은 경우 (모든 파일이 있음) 따라서이 방법으로 분할하면 ||대신에 필요 합니다 &&. 내 질문 자체 아래의 첫 번째 의견을 참조하십시오.
와일드 카드

2
@DopeGhoti : not (a and b)와 동일합니다 (not a) or (not b). 참조 en.wikipedia.org/wiki/De_Morgan%27s_laws
cuonglm

1
목요일이어야합니다. 나는 목요일에 교수형에 처할 수 없었다. 수정하고 나는 후손을 위해 입을 다물고 있습니다.
DopeGhoti

-1

그룹화를 위해서만 사용하고 싶지만 실제로 서브 쉘을 생성합니까? (어떻게 알 수 있습니까?)

예,의 명령 (...)은 서브 쉘에서 실행됩니다.

서브 쉘에 있는지 테스트하기 위해 현재 쉘의 PID와 대화식 쉘의 PID를 비교할 수 있습니다.

echo $BASHPID; (echo $BASHPID); 

괄호가 서브 쉘을 생성하고 중괄호가 생성되지 않음을 보여주는 출력 예 :

$ echo $BASHPID; (echo $BASHPID); { echo $BASHPID;}
50827
50843
50827
$ 

6
()subshell을 생성합니다 {}.
아마도

@heemayl, 내의 다른 부분 내가 할 수있는 몇 가지 방법이 문제는-가요 참조 또는 증명 양산되고 내 화면에 서브 쉘의 사실은? (실제로 별도의 질문이 될 수 있지만 여기서 알아두면 좋을 것입니다.)
Wildcard

1
@heemayl 당신이 맞아요! 나는 echo $$ && ( echo $$ )PID를 비교하려고했지만 그것들은 동일하지만 당신이 틀렸다는 의견을 제출하기 직전에 다른 것을 시도했습니다. echo $BASHPID && ( echo $BASHPID )다른 PID를 제공
David King

1
@heemayl echo $BASHPID && { echo $BASHPID; }은 귀하가 제안한 것과 동일한 PID를 제공합니다. 교육에 감사드립니다
David King

@DavidKing,을 사용하는 테스트 명령에 감사드립니다 $BASHPID.
와일드 카드
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.