불필요한 고양이를 걱정해야합니까?


50

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

비교

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

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

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


30
시스템에서 실제로 고양이 프로세스를 시작하는 것
보다이

4
@ 마이클 : 100 % 동의합니다. 내 컴퓨터가 인스턴스화를 낭비하는 것보다 오래된 유즈넷 상을 연결하는 데 더 많은 시간이 걸렸습니다 cat. 그러나 내가 여기 더 큰 문제는 생각 코드의 가독성 종종 있다 성능에 비해 우선 순위입니다. 실제로 더 빨리 쓸 수 있을 때는 왜 안될까요 ? 문제를 지적하면 cat일반적으로 파이프 라인과 프로세스를 더 잘 이해하게됩니다. 다음 번에 이해할 수있는 코드를 작성하기 위해 노력할 가치가 있습니다.
Caleb

3
실제로 첫 번째 형식이 마음에 들지 않는 또 다른 이유가 있습니다 . 파이프 라인 의 시작 부분 에 다른 명령을 추가 하려면 인수도 이동해야하므로 편집이 더 짜증납니다. (물론 이것이 사용을 의미하는 것은 아닙니다 cat. 기능과 리디렉션 사용에 대한 Caleb의 요점도이를 해결합니다.)
Cascabel


1
그날 저녁 직장에서 일을 거부했습니다. stackoverflow를 열고 "불필요한 고양이에 관심을 가져야합니까?"라는 제목의 질문을 찾습니다. 그리고 노숙자 동물과 프로그래머를
만나

답변:


46

"정확한"답변은 물론 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은 실제로 따라 가기가 쉽고 개별 구성 요소는 해당 기능으로 쉽게 디버깅 할 수 있습니다.


26
나는 그것이 <file명령 앞에 올 수 있다는 것을 몰랐다 . 이것은 내 모든 문제를 해결합니다!

3
@Tim : Bash와 Zsh는 모두 추악하다고 생각하지만 지원합니다. 코드가 예쁘고 유지 관리 가능하다는 것이 걱정되면 일반적으로 함수를 사용하여 정리합니다. 마지막 편집을 참조하십시오.
Caleb

8
@Tim <file은 명령 줄의 어느 곳에 <file grep needle나 올 수 있습니다 : 또는 grep <file needle또는 grep needle <file. 루프 및 그룹화와 같은 복잡한 명령은 예외입니다. 거기에서 done/ }/ )/ etc를 닫은 후에 리디렉션이 이루어져야합니다 . @Caleb 모든 Bourne / POSIX 쉘에 들어 있습니다. 그리고 나는 그것이 추한 것에 동의하지 않습니다.
Gilles 'SO- 악한 중지'

9
@Gilles는 떠들썩한 파티에서 당신은 대체 할 수 $(cat /some/file)$(< /some/file)같은 일을하지만, 프로세스를 생성 방지한다.
CJM

3
$(< /some/file)휴대 성이 제한되어 있음을 확인하십시오 . bash에서는 작동하지만 BusyBox ash 또는 FreeBSD sh에서는 작동하지 않습니다. 마지막 세 개의 쉘이 모두 가까운 사촌이기 때문에 아마도 대시에서 작동하지 않을 것입니다.
dubiousjim

22

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

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되지 않습니다.

2
성능 관련 :이 테스트는 스트림 oletange.blogspot.dk/2013/10/useless-use-of-cat.html
Ole Tange

2
@OleTange. 다른 테스트가 있습니다 : truncate -s10G a; time wc -c < a; time cat a | wc -c; time cat a | cat | wc -c. 그림으로 들어가는 많은 매개 변수가 있습니다. 성능 불이익은 0에서 100 % 사이입니다. 어쨌든 나는 형벌이 부정적 일 수 없다고 생각합니다.
Stéphane Chazelas

2
wc -c바로 가기가 있기 때문에 매우 독특한 경우입니다. 대신 대신 내 예제에서 wc -w비교할 수 있습니다 grep(예 : 처리가 거의 없음- '<' 가 차이를 만들 있는 상황 ).
Ole Tange

@OleTange, 심지어 ( wc -wLinux 4.9 amd64의 C 로켈에서 1GB 스파 스 파일) 고양이 접근 방식은 멀티 코어 시스템에서 23 % 더 오래 걸리고 하나의 코어에 바인딩 할 때 5 %가 걸립니다. 하나 이상의 코어에서 데이터에 액세스함으로써 발생하는 추가 오버 헤드를 보여줍니다. 파이프의 크기를 변경하고, 다른 데이터를 사용하고, 실제 I / O와 관련된 경우 splice ()를 사용하는 cat 구현을 사용하면 다른 결과를 얻을 수 있습니다. 모두 그림에 나오는 많은 매개 변수가 있음을 확인 어쨌든 cat도움이되지 않습니다.
Stéphane Chazelas

1
1GB 파일을 가진 저에게 wc -w똑바로 간단한 grep에 있다면 약 2 % ~ 15 %의 차이입니다. 이상하게도, NFS 파일 공유에 있다면 cat( gist.github.com/rdp/7162414833becbee5919cda855f1cb86 ) Weird ...
rogerdpack에서

16

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

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

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


내가 사용 동의 <그것은 multipipeline의 구문 일관성을 파괴하기 때문에, 코드가 덜 읽을 수 번.
A.Danischewski

@Jim 다음과 <같은 별칭을 만들어 가독성을 해결 alias load='<'한 다음 eg를 사용하십시오 load file | sed .... 별칭은 실행 후 스크립트에서 사용할 수 있습니다 shopt -s expand_aliases.
niieani

1
예, 별칭에 대해 알고 있습니다. 그러나이 별명이 기호로 단어를 대체하지만 독자가 개인 별명 설정에 대해 알아야하므로 이식성이 떨어집니다.
Jim

8

여기에 다른 답변이 직접 언급하지 않은 것 중 하나는 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프로세스 를 생성하는 추가 작업이 아니라 파일의 바이트를 한 번이 아니라 두 번 읽고 쓰는 추가 작업이기도합니다. 실제로 실제로 말하면 현대 시스템에서는 큰 차이가 없습니다. 시스템에서 몇 마이크로 초의 불필요한 작업을 수행 할 수 있습니다. 그러나 배포하려는 스크립트의 경우, 이미 전력이 부족한 컴퓨터에서 스크립트를 사용하는 사람들에게 잠재적 인 경우 몇 마이크로 초가 많은 반복 작업을 추가 할 수 있습니다.


2
추가 사용의 오버 헤드 테스트에 대해서는 oletange.blogspot.dk/2013/10/useless-use-of-cat.html 을 참조하십시오 cat.
Ole Tange

@OleTange : 방금 넘어져서 블로그를 방문했습니다. (1) 대부분 영어로 내용을 볼 때 덴마크어로“Klassisk”,“Flipcard”,“Magasin”,“Mosaik”,“Sidebjælke”,“Øjebliksbillede”라는 단어가 많이 있습니다. ,“Tidsskyder”,“Blog-arkiv”,“Om mig”,“Skrevet”및“Vis kommentarer”(단,“Tweet”,“Like”및 쿠키 배너는 영어입니다). 이것에 대해 알고 있습니까? (2) 눈금 선이 불완전하기 때문에 (2a) 표를 읽는 데 어려움이 있습니다. (2b)“Diff (pct)”의 의미를 이해하지 못합니다.
G-Man

blogspot.dk는 Google이 운영합니다. blogspot.com으로 바꾸십시오. "차이 (pct)"는 퍼센트 cat단위없이 ms로 나눈 ms입니다 cat(예 : 264ms / 216ms = 1.22 = 122 % = 22 % 느림 cat)
Ole Tange
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.