셸의 제어 및 리디렉션 연산자는 무엇입니까? command2 command1 || command2

여러 명령을 다른 기호로 연결하는 온라인 자습서가 종종 있습니다. 예를 들면 다음과 같습니다.

command1 |  command2
command1 &  command2
command1 || command2    
command1 && command2

다른 사람들은 명령을 파일에 연결하는 것 같습니다.

command1  > file1
command1  >> file1

이것들은 무엇입니까? 그들은 무엇을 불렀습니까? 그들은 무엇을합니까? 더 있나요?


이 질문에 대한 메타 스레드. .



답변

이것을 쉘 연산자라고하며 더 많은 것이 있습니다. 두 가지 주요 클래스 인 제어 연산자리디렉션 연산자 중 가장 일반적인 클래스 와 bash 셸과 관련하여 작동하는 방법에 대해 간략하게 설명합니다 .

A. 제어 연산자

쉘 명령 언어에서 제어 기능을 수행하는 토큰.
다음 기호 중 하나입니다.

&   &&   (   )   ;   ;;   <newline>   |   ||

그리고 |&bash에서.

A는 !것입니다 하지 제어 운영자하지만 예약어 . 산술 표현식 내부와 테스트 구조 내부 의 논리 NOT [음수 연산자]가됩니다 (여전히 공백 구분자가 필요함).

A.1리스트 종결 자

  • ; : 첫 번째 결과와 상관없이 다른 명령이 완료된 후 한 명령을 실행합니다.

    command1 ; command2

    첫 번째 command1는 포 그라운드에서 실행되며 완료되면 command2실행됩니다.

    문자열 리터럴에 없거나 특정 키워드 뒤에있는 줄 바꿈 은 세미콜론 연산자와 동일 하지 않습니다 . 목록 ;구분 간단한 명령은 여전히입니다 목록 – 여전히 따라 간단한 명령에 읽을 계속해야 쉘의 파서로 ;목록 또는 목록 – 개행 문자는 전체 명령 목록을 구분 수있는 반면, 실행하기 전에 구분 간단한 명령을. 차이점은 미묘하지만 복잡합니다. 쉘에 줄 바꿈 다음에 데이터를 읽는 데 필요한 명령이 없기 때문에 줄 바꿈은 쉘이 이미 읽은 간단한 명령을 평가할 수있는 지점을 표시하지만 ;세미콜론은 아니.

  • & : 백그라운드에서 명령을 실행하여 동일한 쉘에서 작업을 계속할 수 있습니다.

     command1 & command2

    여기서 command1백그라운드에서 command2시작되고 command1종료 를 기다리지 않고 즉시 포 그라운드에서 실행되기 시작합니다 .

    이후 개행 command1은 선택 사항입니다.

A.2 논리 연산자

  • && : AND 목록을 작성하는 데 사용되며 다른 명령이 성공적으로 종료 된 경우에만 하나의 명령을 실행할 수 있습니다.

     command1 && command2

    여기서는 완료된 command2command1그리고 성공한 경우 에만command1 종료됩니다 (종료 코드가 0 인 경우). 두 명령 모두 포 그라운드에서 실행됩니다.

    이 명령은 또한 쓸 수 있습니다

    if command1
    then command2
    else false
    fi

    또는 단순히 if command1; then command2; fi반환 상태가 무시되는 경우.

  • || : OR 목록을 작성하는 데 사용되며 다른 명령이 성공적으로 종료 된 경우에만 하나의 명령을 실행할 수 있습니다.

     command1 || command2

    여기서는 실패한 command2경우에만 실행됩니다 command1(0 이외의 종료 상태를 반환 한 경우). 두 명령 모두 포 그라운드에서 실행됩니다.

    이 명령은 또한 쓸 수 있습니다

    if command1
    then true
    else command2
    fi

    또는 더 짧은 방법으로 if ! command1; then command2; fi.

    그 주 &&||왼쪽 연관된다; 참조 ||, 쉘 논리 연산자 &&의 우선 순위를 자세한 내용은.

  • !: 이것은 “not”연산자로 작동하지만 (구분자가 있어야 함) 명령의 리턴 상태를 무효화하는 데 사용되는 예약어입니다. 명령이 0이 아닌 상태를 리턴하면 0을 리턴하고 상태 0을 리턴하면 1을 리턴하십시오. 또한 test유틸리티에 대한 논리적 NOT입니다 .

    ! command1
    
    [ ! a = a ]

    그리고 산술 표현식 내부의 진정한 NOT 연산자 :

    $ echo $((!0)) $((!23))
    1 0

A.3 파이프 운영자

  • |: 파이프 연산자, 한 명령의 출력을 다른 명령의 입력으로 전달합니다. 파이프 연산자로 작성된 명령을 파이프 라인 이라고합니다 .

     command1 | command2

    로 인쇄 된 모든 출력 command1은에 입력으로 전달됩니다 command2.

  • |&: 이것은 2>&1 |bash 및 zsh 의 약어입니다 . 한 명령의 표준 출력과 표준 오류를 다른 명령의 입력으로 전달합니다.

    command1 |& command2

A.4 기타 목록 구두점

;;사례 진술 의 끝을 표시하기 위해서만 사용됩니다 . Ksh, bash 및 zsh는 ;&다음 사례 ;;&로 넘어 가고 (ATT ksh 아님) 후속 사례 로 넘어갈 수 있도록 지원 합니다 .

()에 사용되는 그룹 명령 및 서브 쉘에서 그들을 실행합니다. {그리고 }또한 그룹 명령하지만, 서브 쉘에서 그들을 실행되지 않습니다. 쉘 구문에서 다양한 유형의 괄호, 괄호 및 중괄호에 대한 설명은 이 답변 을 참조하십시오 .

B. 리디렉션 연산자

리디렉션 연산자

쉘 명령 언어에서 리디렉션 기능을 수행하는 토큰. 다음 기호 중 하나입니다.

<     >     >|     <<     >>     <&     >&     <<-     <>

이를 통해 명령의 입력 및 출력을 제어 할 수 있습니다. 간단한 명령 내의 어느 곳에 나 나타나거나 명령을 따를 수 있습니다. 리디렉션은 왼쪽에서 오른쪽으로 표시되는 순서대로 처리됩니다.

  • < : 명령을 입력합니다.

    command < file.txt

    command의 내용에서 실행 됩니다 file.txt.

  • <>: 위와 동일하지만 파일이 읽기 전용 대신 읽기 + 쓰기 모드로 열립니다 .

    command <> file.txt

    파일이 존재하지 않으면 생성됩니다.

    이 연산자는 명령이 일반적으로 stdin 에서만 읽기 때문에 거의 사용되지 않지만 여러 가지 특정 상황에서 유용 할 수 있습니다 .

  • > : 명령 출력을 파일로 보냅니다.

    command > out.txt

    위의 출력은 command로 저장 됩니다 out.txt. 파일이 존재하면 해당 내용을 덮어 쓰고 존재하지 않으면 파일이 작성됩니다.

    이 연산자는 종종 표준 오류 또는 표준 출력 으로 인쇄할지 여부를 선택하는 데 사용됩니다 .

    command >out.txt 2>error.txt

    위의 예에서 >표준 출력을 2>리디렉션하고 표준 오류를 리디렉션합니다. 출력을 사용하여 리디렉션 할 수도 1>있지만 이것이 기본값 1이므로 일반적으로 생략되고 간단히로 작성됩니다 >.

    그래서 실행 commandfile.txt그 출력 저장 out.txt및에 오류 메시지 error.txt실행할 것을 :

    command < file.txt > out.txt 2> error.txt
  • >|:와 동일 >하지만 쉘이 ( set -C또는로 set -o noclobber) 덮어 쓰기를 거부하도록 구성된 경우에도 대상을 덮어 씁니다 .

    command >| out.txt

    경우 out.txt존재의 출력 command내용을 대체합니다. 존재하지 않는 경우 작성됩니다.

  • >>: >대상 파일이 존재하는 경우 새 데이터가 추가된다는 점을 제외하고 와 동일 합니다.

    command >> out.txt

    경우 out.txt존재의 출력은 command그 안에 이미 무엇이든 후, 여기에 추가됩니다. 존재하지 않는 경우 작성됩니다.

  • &>, >&, >>&&>>(비표준). 표준 오류와 표준 출력을 각각 대체하거나 추가하여 리디렉션하십시오.

    command &> out.txt

    의 표준 오류와 표준 출력 command이 모두에 저장되어 out.txt해당 내용을 덮어 쓰거나 존재하지 않는 경우 작성합니다.

    command &>> out.txt

    위와 같이 out.txt존재 하는 경우 출력과 오류 command가 추가됩니다.

    &>변형에 기인 bash그동안, >&변형은 CSH (년 이전)에서 비롯됩니다. 둘 다 다른 POSIX 셸 연산자와 충돌하므로 이식 가능한 sh스크립트에는 사용해서는 안됩니다 .

  • <<: 여기 문서입니다. 종종 여러 줄 문자열을 인쇄하는 데 사용됩니다.

     command << WORD
         Text
     WORD

    여기에, command그것은의 다음 발생을 찾을 때까지 모든 것을 걸릴 것입니다 WORD, Text입력으로, 위의 예에서. WORD종종 EoF또는 그 변형 이지만 , 원하는 영숫자 문자열 일 수 있습니다. 때 WORD인용, 여기에 문서의 텍스트는 문자 그대로 처리하고 더 확장 (예 : 변수) 수행되지 않습니다. 인용 부호가 없으면 변수가 확장됩니다. 자세한 내용은 bash 매뉴얼을 참조하십시오 .

    출력 command << WORD ... WORD을 다른 명령 또는 명령 으로 직접 파이프하려면 파이프를와 같은 행에 << WORD배치해야합니다. 종료 단어 다음에 또는 다음 행에 파이프를 배치 할 수 없습니다. 예를 들면 다음과 같습니다.

     command << WORD | command2 | command3...
         Text
     WORD
  • <<<: 여기 문서와 유사하지만 한 줄로 된 문자열입니다. 이것들은 유닉스 포트 또는 rc (원산지) zsh, ksh, yash 및 bash의 일부 구현에만 존재합니다.

    command <<< WORD

    주어진대로 WORD확장되고 값은에 입력으로 전달됩니다 command. 이것은 종종 변수의 내용을 입력으로 명령에 전달하는 데 사용됩니다. 예를 들면 다음과 같습니다.

     $ foo="bar"
     $ sed 's/a/A/' <<< "$foo"
     bAr
     # as a short-cut for the standard:
     $ printf '%s\n' "$foo" | sed 's/a/A/'
     bAr
     # or
     sed 's/a/A/' << EOF
     $foo
     EOF

다른 몇 가지 연산자 ( >&-, x>&y x<&y)를 사용하여 파일 설명자를 닫거나 복제 할 수 있습니다. 그들에 대한 자세한 내용은 (쉘의 설명서의 관련 섹션을 참조하십시오 여기에 떠들썩한 파티를 위해 예를 들어).

그것은 Bourne과 같은 쉘의 가장 일반적인 연산자에만 적용됩니다. 일부 셸에는 몇 가지 추가 리디렉션 연산자가 있습니다.

Ksh, bash 및 zsh에도 construct <(…)>(…)있으며 =(…)(후자 zsh만). 이는 리디렉션이 아니라 프로세스 대체 입니다.


답변

‘>’에 관한 경고

단지 I / O 리디렉션 (에 대해 배운 유닉스 초보자 <와는 >) 종종 같은 것들을 시도

명령 ... input_file > the_same_file

또는

명령 ... < 파일      > the_same_file

또는 거의 동등하게

고양이 파일 | 명령 ...> the_same_file

( grep, sed, cut, sort, 그리고 spell사람들이 이런 구조에 사용하는 유혹 명령의 예입니다.) 사용자는 이러한 시나리오가 비어되는 파일이 발생할 것을 발견 놀랄 수 있습니다.

다른 답변에서 언급되지 않은 뉘앙스 는 bash (1)Redirection 섹션의 첫 번째 문장에 숨어 있습니다 .

명령이 실행되기 전에
셸이 해석하는 특수 표기법을 사용하여 입력 및 출력을 리디렉션 할 수 있습니다 .

처음 5 개 단어는 굵게, 기울임 꼴, 밑줄, 확대, 깜박임, 빨간색으로 표시되고 빨간색 삼각형의 느낌표아이콘으로 표시되어 명령을 실행하기 전에 셸이 요청 된 리디렉션을 수행한다는 사실을 강조
해야합니다 . 또한 기억하십시오

출력을 재 지정하면 파일을 쓰기 위해 열린다.… 파일이 존재하지 않으면 파일이 작성됩니다. 존재하는 경우 크기가 0으로 잘립니다.

  1. 따라서이 예에서

    sort roster > roster

    rostersort프로그램 실행을 시작 하기 전에 파일을 잘라서 잘라서 잘라냅니다 (즉, 내용을 모두 버림) . 당연히, 데이터를 복구하기 위해 아무것도 할 수 없습니다.

  2. 순진하게 기대할 수도 있습니다.

    tr "[:upper:]" "[:lower:]" < poem > poem

    더 좋을 수도 있습니다. 쉘은 왼쪽에서 오른쪽으로 경로 재 지정을 처리 하므로, 쓰기를 위해 열기 전에 (표준 출력을 위해) poem읽기 위해 ( tr표준 입력을 위해) 열립니다. 그러나 도움이되지 않습니다. 이 일련의 조작으로 두 개의 파일 핸들이 생성되지만 둘 다 동일한 파일을 가리 킵니다. 셸에서 읽을 파일을 열면 내용이 그대로 있지만 프로그램이 실행되기 전에 여전히 내용이 잘립니다. 

그래서 어떻게해야합니까?

솔루션은 다음과 같습니다.

  • 실행중인 프로그램에 출력 위치를 지정하는 고유 한 내부 기능이 있는지 확인하십시오. 이것은 종종 -o(또는 --output=) 토큰으로 표시됩니다 . 특히,

    sort roster -o roster

    대략적으로

    sort roster > roster

    첫 번째 경우를 제외하고 sort프로그램은 출력 파일을 엽니 다. 때까지 그리고 출력 파일을 열 수없는만큼 똑똑 후에 는 입력 파일 (들)을 모두 읽을 수있다.

    이와 유사하게, 적어도 일부 버전 sed-i(편집 내가 다시 입력 파일로 출력 출력을 작성하는 데 사용할 수있는 N 장소) 옵션을 (다시, 이후 모든 입력이 읽은). 같은 편집자 ed/ ex, emacs, pico, 및 vi/은 vim
    사용자가 텍스트 파일을 편집하고 원본 파일에서 편집 된 텍스트를 저장할 수 있습니다. 있습니다 ed(적어도)는 비 대화식으로 사용할 수 있습니다.

    • vi관련 기능이 있습니다. 을 입력 하면에 편집 버퍼의 내용을 출력하고 출력을 읽고이를 버퍼에 삽입합니다 (원본 내용을 바꿉니다).:%!commandEntercommand
  • 간단하지만 효과적인:

    명령input_file > temp_file   && mv temp_file  input_file

    이는 input_file링크 인 경우 별도의 파일로 대체 될 수 있는 단점이 있습니다. 또한 새 파일은 기본 보호 기능으로 소유합니다. 특히 원본 input_file이 아니더라도 파일을 세계에서 읽을 수있게 될 위험이 있습니다 .

    변형 :

    • commandinput_file > temp_file && cp temp_file input_file && rm temp_file
      여전히 (잠재적으로) temp_file세상을 읽을 수있게 할 것입니다 더 나은 :
    • cp input_file temp_file && commandtemp_file > input_file && rm temp_file
      이로 인해 파일의 링크 상태, 소유자 및 모드 (보호)가 유지되며 잠재적으로 I / O의 2 배가됩니다. (당신은 같은 옵션을 사용해야 할 수도 -a-p에 대한 cp
      특성을 보존하도록 지시 할 수 있습니다.)
    • commandinput_file > temp_file &&
      cp --attributes-only --preserve=all input_file temp_file &&
      mv temp_file input_file
      (가독성을 위해 별도의 행으로 분리됨) 파일의 모드 (루트 인 경우 소유자)를 유지하지만 사용자가 소유 한 파일 (루트하지 않은 경우)을 만들고 새 파일로 만듭니다. 별도의 파일.
  • 이 블로그
    ( “파일 내”편집)는 제안하고 설명합니다.

    {rm input_file   &&   command …> input_file ; } < input_file

    이를 위해서는 command표준 입력을 처리 할 수 ​​있어야하지만 거의 모든 필터가 가능합니다. 블로그 자체는 이것을 위험한 kludge라고하며 사용을 권장하지 않습니다. 그리고 이것은 또한 당신이 소유하고 기본 권한을 가진 새로운 별도의 파일 (아무것도 링크되지 않은)을 만듭니다.

  • moreutils 패키지에는 다음과 같은 명령이 있습니다 sponge.

    명령input_file | 스폰지 the_same_file

    자세한 내용은 이 답변 을 참조하십시오.

나에게 완전히 놀랐던 것이있다 :
syntaxerror 말한다 :

[이러한 솔루션의 대부분은] “읽기 전용”당신이 있다는 것을 의미 읽기 전용 파일 시스템에 실패 $HOME 할 것이다 쓸 수 있지만 /tmp됩니다 읽기 전용 (기본적으로). 예를 들어, Ubuntu가 있고 복구 콘솔로 부팅 한 경우가 일반적입니다. 또한, 여기-문서 운영자 <<<가 필요로 하나가 작동하지 않습니다 /tmp읽기 / 쓰기
그것뿐만 아니라 거기에 임시 파일을 쓰기 때문입니다.
(cf. 이 질문 에는 strace‘d 출력 포함됩니다 )

이 경우 다음이 작동 할 수 있습니다.

  • 고급 사용자의 경우 :
    명령이 입력이 같은 출력 데이터의 같은 양을 생산하기 위해 보장되어있는 경우 (예를 들어, sort또는 tr 없이-d 또는 -s옵션), 당신은 시도 할 수 있습니다

    명령input_file | dd of = the_same_file conv = notrunc

    참조 이 답변
    하고 이 응답 명령이 입력이 같은 출력 데이터의 같은 양을 생산하기 위해 보장되어있는 경우 작동 위의 설명을 포함한 자세한 내용은, 대안 이하 (예를 들어, grep또는 cut). 이 답변은 여유 공간이 필요하지 않거나 매우 적은 이점이 있습니다. 위의 형식에 대한 답

    은 시스템이 전체 입력 (이전) 파일과 출력 (새) 파일을 동시에 보유 할 수있는 충분한 여유 공간이 필요하다는 것을 분명히 요구합니다. 이는 대부분의 다른 솔루션 (예 : 및 )에도 해당되지 않습니다. 예외 : 여유 공간이 많이 필요할 것입니다 .commandinput_file > temp_file && …sed -ispongesort … | dd …sort 출력을 쓰기 전에 모든 입력을 읽어야하며, 모든 파일이 임시 파일에있는 것은 아니지만 대부분 버퍼링합니다.

  • 고급 사용자 만 해당 :
    명령input_file 1 <> the_same_file

    dd

    의 답변 과 동일 할 수 있습니다 . 이 구문은 파일 디스크립터에서 이름 지정된 파일을 잘라 내지 않고 입력 및 출력 모두에 대해
    및 의 조합으로 엽니 다 . 참고 : 일부 프로그램 (예 : 및 )은 입력과 출력이 동일한 파일임을 감지 할 수 있으므로이 시나리오에서 실행을 거부 할 수 있습니다.
    위의 설명에 대해서는 이 대답 을 참조 하고 명령이 input이 있거나 같은 양의 출력 데이터를 생성하도록 보장 된 경우이 답변을 작동시키는 스크립트를 참조하십시오 .
    경고 : Peter의 스크립트를 테스트하지 않았으므로 보증하지 않습니다.n<> filen n<n>catgrep

그래서 질문은 무엇입니까?

이것은 U & L에서 인기있는 주제였습니다. 다음 질문에서 다룹니다.

… 그리고 그것은 슈퍼 유저 나 Ask Ubuntu를 포함하지 않습니다. 위의 질문에 대한 답변의 많은 정보를이 답변에 통합했지만 전부는 아닙니다. (자세한 내용은 위에 나열된 질문과 답변을 읽으십시오.)

추신 : 나는 위에 인용 한 블로그와 아무런 관련 이 없습니다 .


답변

더 관찰에 ;, &, ()

  • terdon의 답변에있는 일부 명령은 null 일 수 있습니다. 예를 들어

    command1 ;

    (없음 command2). 이것은

    command1

    (즉, 단순히 command1포 그라운드에서 실행 되고 완료 될 때까지 기다립니다.

    command1 &

    (no command2)는 command1백그라운드에서 시작된 다음 다른 쉘 프롬프트를 즉시 발행합니다.

  • 대조적으로 command1 &&,, command1 ||command1 |말이되지 않습니다. 이들 중 하나를 입력하면, 쉘은 아마도 명령이 다른 행에 계속 있다고 가정합니다. 일반적으로로 설정된 보조 (계속) 셸 프롬프트가 표시 >되고 계속 읽습니다. 쉘 스크립트에서는 다음 줄을 읽고 이미 읽은 내용에 추가합니다. (주의 : 이것은 당신이 일어나고 싶지 않을 수도 있습니다.)

    참고 : 일부 셸의 일부 버전은 이러한 불완전한 명령을 오류로 취급 할 수 있습니다. 이러한 경우 (사실이나,에 어떤 당신이 긴 명령을 경우), 당신은 백 슬래시 (넣을 수 있습니다 \다른 행에 명령을 읽는 계속 쉘에게 줄 끝에) :

    command1  &&  \
    command2

    또는

    find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f \
                            -newer some_existing_file -user fred -readable -print
  • terdon 말한다대로 ()그룹 명령을 사용할 수 있습니다. 그들이 그 토론과“실제로 관련이 없다”는 진술은 논쟁의 여지가 있습니다. terdon의 답변에있는 명령 중 일부는 명령 그룹 일 수 있습니다 . 예를 들어

    ( command1 ; command2 )  &&  ( command3; command4 )

    이것을한다 :

    • 실행 command1하고 완료 될 때까지 기다리십시오.
    • 그런 다음 첫 번째 명령을 실행 한 결과에 관계없이 실행 command2하고 완료 될 때까지 기다리십시오.
    • 그런 다음 command2성공하면

      • 실행 command3하고 완료 될 때까지 기다리십시오.
      • 그런 다음 해당 명령을 실행 한 결과에 관계없이 실행 command4하고 완료 될 때까지 기다리십시오.

      command2실패한 경우 명령 행 처리를 중지하십시오.

  • 외부 괄호는 |매우 밀접하게 바인딩되므로

    command1 | command2 || command3

    에 해당

    ( command1 | command2 )  ||  command3

    &&||보다 긴밀한 결합 ;때문에,

    command1 && command2 ; command3

    에 해당

    ( command1 && command2 ) ;  command3

    즉, 및 / 또는 command3의 종료 상태에 관계없이 실행됩니다 .command1command2


답변