불필요한 고양이를 걱정해야합니까? 특히 첫 번째 명령에 여러 줄 인수가

많은 명령 줄 유틸리티는 파이프 또는 파일 이름 인수로 입력을받을 수 있습니다. 긴 쉘 스크립트의 cat경우, 특히 첫 번째 명령에 여러 줄 인수가 필요한 경우 체인을 시작하여 더 읽기 쉽습니다.

비교

sed s/bla/blaha/ data \
| grep blah \
| grep -n babla

cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla

후자의 방법은 덜 효율적입니까? 그렇다면, 스크립트가 실행되는지, 즉 1 초에 한 번 신경을 쓸만한 차이가 있습니까? 가독성의 차이는 크지 않습니다.



답변

“정확한”답변은 물론 The Useless Use of catAward에 의해 제공됩니다 .

cat의 목적은 파일을 연결 (또는 “catenate”)하는 것입니다. 파일이 하나 인 경우 전혀 연결하지 않으면 시간이 낭비되고 프로세스 비용이 발생합니다.

코드를 다르게 읽을 수 있도록 cat을 인스턴스화하면 하나 이상의 프로세스와 필요하지 않은 하나 이상의 입력 / 출력 스트림 세트가 만들어집니다. 일반적으로 스크립트의 실제 보류는 비효율적 인 루프와 실제 처리입니다. 대부분의 최신 시스템에서는 하나의 추가 기능 cat이 성능을 저하시키지 않지만 코드를 작성하는 다른 방법 은 거의 항상 있습니다.

참고로, 대부분의 프로그램은 입력 파일에 대한 인수를 허용 할 수 있습니다. 그러나 <STDIN 스트림이 필요할 때마다 사용할 수있는 셸 내장이 항상 있으므로 이미 실행중인 셸 프로세스에서 작업을 수행하여 하나의 프로세스를 절약 할 수 있습니다.

당신이 쓰는 곳에서 창의력을 발휘할 수도 있습니다. 일반적으로 다음과 같이 출력 경로 재 지정 또는 파이프를 지정하기 전에 명령 끝에 위치합니다.

sed s/blah/blaha/ < data | pipe

그러나 그런 식일 필요는 없습니다. 심지어 먼저 올 수 있습니다. 예를 들어 예제 코드는 다음과 같이 작성할 수 있습니다.

< data \
    sed s/bla/blaha/ |
    grep blah |
    grep -n babla

스크립트 가독성이 문제이고 코드가 지저분하여 줄을 추가하기 cat가 더 쉬워 질 것으로 예상되는 경우 코드를 정리하는 다른 방법이 있습니다. 스크립트를 나중에 쉽게 알아볼 수 있도록 많이 사용하는 것 중 하나는 파이프를 논리적 집합으로 분리하여 함수에 저장하는 것입니다. 그러면 스크립트 코드가 매우 자연스러워지고 pipline의 한 부분을 쉽게 디버깅 할 수 있습니다.

function fix_blahs () {
    sed s/bla/blaha/ |
    grep blah |
    grep -n babla
}

fix_blahs < data

그런 다음 계속할 수 있습니다 fix_blahs < data | fix_frogs | reorder | format_for_sql. 그렇게 읽는 pipleline은 실제로 따라 가기가 쉽고 개별 구성 요소는 해당 기능으로 쉽게 디버깅 할 수 있습니다.


답변

다음은 몇 가지 단점을 요약 한 것입니다.

cat $file | cmd

위에

< $file cmd
  • 첫째, 참고 사항 : 의도적으로 논의의 목적으로 큰 따옴표가 누락되었습니다 $file. 의 경우 cat항상 예외입니다 zsh. 리디렉션의 경우 이는 대화식 (스크립트가 아닌)에서만 bash또는 ksh88일부 다른 쉘의 경우에만 문제가됩니다.
  • 가장 많이 인용되는 단점은 추가 프로세스가 생성되는 것입니다. cmd내장 된 경우 와 같은 일부 쉘에서는 2 개의 프로세스입니다 bash.
  • 기본적으로 cat제공 되는 쉘을 제외하고는 여전히 성능 측면에서 실행되고 추가 명령이 실행됩니다 (물론로드되고 초기화됩니다 (및 연결된 라이브러리)).
  • 아직도 성능 전면에 큰 파일을, 그 시스템이 교대로 예약해야합니다 의미 catcmd프로세스를 끊임없이 채워 파이프 버퍼를 비 웁니다. 해도 cmd않는 1GBread()시스템은 한 번에 호출 제어 사이에왔다 갔다해야합니다 catcmd파이프가 한 번에 데이터의 몇 킬로바이트 이상을 보유 할 수 없기 때문에.
  • 일부 cmd의 (등 wc -c자신의 표준 입력들이 함께 할 수없는 일반 파일 인 경우) 몇 가지 최적화를 할 수있는 cat | cmd자신의 표준 입력 후 단지 파이프와 같이가. cat파이프를 사용 seek()하면 파일 내에서 파이프를 사용할 수 없습니다 . 같은 명령을 위해 tac또는 tail그와 함께한다는 뜻입니다, 그 성능에 큰 차이가 cat그들이 필요로하는 메모리의 전체 입력을 저장합니다.
  • cat $file, 심지어는 더 올바른 버전 cat -- "$file"같은 일부 특정 파일 이름을 제대로 작동하지 않습니다 -(또는 --help또는로 시작하는 것을 -당신이를 잊어 버린 경우 --). 하나 cat를 사용해야 한다고 주장한다면 아마도 cat < "$file" | cmd신뢰성을 대신 사용해야 합니다.
  • 경우 $file(액세스가 거부, … 존재하지 않음) 읽기 위해 열 수 없습니다, < "$file" cmd(쉘) 일관성 오류 메시지를보고 할 것 없는 실행 cmd하면서, cat $file | cmd여전히 실행 cmd하지만 그것은 빈 파일처럼 표준 입력이 찾고. 즉 < file cmd > file2, 와 같은 것들을 열 수 없으면 file2클로버 file되지 않습니다.

답변

퍼팅 <file파이프 라인의 마지막에하는 것보다 덜 읽을 cat file시작에. 자연 영어는 왼쪽에서 오른쪽으로 읽습니다.

퍼팅 <file에게 파이프 라인의 시작하는 것도 고양이보다 읽을 수있는, 내가 말할 것입니다. 단어는 기호, 특히 잘못된 방향을 가리키는 기호보다 더 읽기 쉽습니다.

를 사용 cat하면 command | command | command형식이 유지 됩니다.


답변

여기에 다른 답변이 직접 언급하지 않은 것 중 하나는 cat이와 같이 사용하는 것이 “무의미한”고양이 프로세스가 생성되지 않는다는 의미에서 “무용지물”이 아니라는 것입니다. “불필요한 작업 만하는 고양이 프로세스가 생성된다”는 의미에서 쓸모가 없습니다.

이 두 경우의 경우 :

sed 's/foo/bar/' somefile
<somefile sed 's/foo/bar/'

쉘은 sed 프로세스를 시작하여 somefile 또는 stdin (각각)을 읽은 다음 일부 처리를 수행합니다. 줄 바꿈이 될 때까지 읽은 다음 해당 줄의 첫 번째 ‘foo'(있는 경우)를 ‘bar’로 바꿉니다. 그 줄을 stdout과 루프에 연결하십시오.

다음의 경우 :

cat somefile | sed 's/foo/bar/'

쉘은 고양이 프로세스와 sed 프로세스를 생성하고 고양이의 stdout을 sed의 stdin에 연결합니다. cat 프로세스는 파일에서 몇 킬로바이트 또는 메가 바이트 청크를 읽은 다음 stdout에 씁니다. 여기서 sed sommand는 위의 두 번째 예에서와 같이 픽업됩니다. sed가 해당 청크를 처리하는 동안 cat은 다른 청크를 읽고 sed가 다음 작업을 위해 stdout에 씁니다.

즉, cat명령 을 추가하여 필요한 추가 작업은 추가 cat프로세스 를 생성하는 추가 작업이 아니라 파일의 바이트를 한 번이 아니라 두 번 읽고 쓰는 추가 작업이기도합니다. 실제로 실제로 말하면 현대 시스템에서는 큰 차이가 없습니다. 시스템에서 몇 마이크로 초의 불필요한 작업을 수행 할 수 있습니다. 그러나 배포하려는 스크립트의 경우, 이미 전력이 부족한 컴퓨터에서 스크립트를 사용하는 사람들에게 잠재적 인 경우 몇 마이크로 초가 많은 반복 작업을 추가 할 수 있습니다.


답변