원치 않는 고양이에 관심을 가져야 할까요?

원치 않는 고양이에 관심을 가져야 할까요?

많은 명령줄 유틸리티는 파이프 또는 파일 이름 인수에서 입력을 받을 수 있습니다. 긴 쉘 스크립트의 경우 체인을 시작하면 cat가독성이 더 높아집니다. 특히 첫 번째 명령에 여러 줄의 인수가 필요한 경우 더욱 그렇습니다.

비교하다

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

그리고

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

후자의 접근 방식이 덜 효율적인가요? 그렇다면 스크립트 실행 여부(예: 1초에 한 번)를 신경 쓸 만큼 차이가 있습니까? 가독성의 차이는 크지 않습니다.

답변1

물론 "최종" 대답은 다음과 같습니다.cat수상의 쓸모없는 사용.

cat의 목적은 파일을 연결(또는 "연결")하는 것입니다. 단순한 파일인 경우 다른 것과 연결하는 것은 시간 낭비이며 프로세스 비용이 많이 듭니다.

코드가 다르게 읽을 수 있도록 cat을 인스턴스화하면 프로세스와 불필요한 입력/출력 스트림 세트만 추가됩니다. 종종 스크립트의 실제 걸림돌은 비효율적인 루핑과 실제 처리입니다.대부분의 최신 시스템에서는 추가 방법이 cat성능에 영향을 미치지 않지만 거의 항상 코드를 작성하는 다른 방법이 있습니다.

이미 알고 있듯이 대부분의 프로그램은 입력 파일의 인수를 받아들일 수 있습니다. 그러나 STDIN 스트림이 필요할 때마다 <이미 실행 중인 쉘 프로세스에서 작업을 수행하여 프로세스를 저장하는 내장 쉘을 사용하는 것이 항상 가능합니다 .

글을 쓰는 위치에 따라 창의력을 발휘할 수도 있습니다. 일반적으로 다음과 같이 출력 리디렉션이나 파이프가 지정되기 전에 명령 끝에 배치됩니다.

sed s/blah/blaha/ < data | pipe

그러나 반드시 그런 것은 아닙니다. 먼저 올 수도 있습니다. 예를 들어 샘플 코드는 다음과 같이 작성할 수 있습니다.

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

스크립트의 가독성을 중요하게 생각하고 코드가 너무 복잡해서 줄을 추가하면 cat이해하기 쉬워질 것으로 예상되는 경우 코드를 정리하는 다른 방법이 있습니다. 제가 자주 사용하는 한 가지 방법은 파이프라인을 논리적 세트로 나누어 함수에 저장하는 것입니다. 이렇게 하면 나중에 스크립트를 더 쉽게 이해할 수 있습니다. 이렇게 하면 스크립팅 코드가 매우 자연스러워지고 파이프라인의 모든 부분을 디버그하기가 더 쉬워집니다.

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

fix_blahs < data

그런 다음 계속할 수 있습니다 fix_blahs < data | fix_frogs | reorder | format_for_sql. 이와 같은 파이프라인은 정말 이해하기 쉽고 개별 구성 요소는 해당 기능에서 쉽게 디버깅할 수 있습니다.

답변2

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

cat $file | cmd

초과하다

< $file cmd
  • 첫째, 참고 사항: 위의 큰따옴표가 누락되었습니다(의도적으로 이 논의의 목적을 위해) $file. 리디렉션 의 경우 cat이는 항상 문제입니다 zsh. 리디렉션의 경우 bash또는 ksh88bashPOSIX 모드를 포함한 일부 다른 셸의 경우 스크립트가 아닌 대화형으로만 문제가 됩니다.

  • 가장 일반적으로 언급되는 단점은 추가 프로세스가 생성된다는 것입니다. cmd일부 쉘에서는 내장된 경우 2개의 프로세스도 생성됩니다(예 : bash.

  • 여전히 성능 측면에서는 cat내장 셸 외에(물론 로딩 및 초기화(및 링크되는 라이브러리)와 함께) 추가 명령이 실행됩니다.

  • 성능 측면에서 볼 때, 이는 대용량 파일의 경우 시스템이 일정 catcmd프로세스를 번갈아 가며 파이프 버퍼를 지속적으로 채우고 비워야 함을 의미합니다. 대규모 시스템 호출을 cmd할 때에도 파이프는 한 번에 몇 킬로바이트 이상의 데이터를 보유할 수 없기 때문에 제어를 앞뒤로 전환해야 합니다 .1GBread()catcmd

  • cmd일부 s(예: ) 는 표준 입력이 일반 파일일 때 일부 최적화를 수행할 수 있지만 표준 입력이 파이프일 뿐이므로 wc -c그렇게 할 수 없습니다 . 파이프 cat | cmd의 경우 cat이는 seek()파일에 포함될 수 없음을 의미합니다. tac또는 이와 같은 명령 의 경우 전체 입력을 메모리에 저장해야 하므로 tail성능에 큰 차이가 있습니다 .cat

  • cat $file, 심지어 더 정확한 버전일지라도 일부 특정 파일 이름(또는 다음으로 시작하는 파일 이름을 잊은 경우)에서는 cat -- "$file"제대로 작동하지 않습니다 . 어떤 사람이 그것을 사용하려고 한다면 신뢰성을 보장하기 위해 아마도 그렇게 해야 할 것입니다.---help---catcat < "$file" | cmd

  • 읽기 위해 열 수 없는 경우 $file(액세스 거부, 존재하지 않음...) < "$file" cmd일관된 오류 메시지가 보고되며(셸에서)아니요run cmd, while 은 cat $file | cmd여전히 ​​run cmd이지만 표준 입력은 빈 파일처럼 보입니다. 이는 또한 이와 같은 경우 < file cmd > file2열 수 없으면 file2파괴되지 않는다는 것을 의미합니다.file

    즉, cmd file > file2출력 파일이 항상 (셸을 통해) 열리는 순서 가 아닌 입력 및 출력 파일이 열리는 순서를 선택할 수 있습니다.앞으로입력 파일(by cmd)을 사용하는 경우 이는 거의 바람직하지 않습니다.

    cmd1 < file | cmd2 > file2그러나 위치 cmd1와 위치 및 리디렉션을 동시에 독립적으로 실행하는 데 도움이 되지 않으며 열 수 없을 때 깨지거나 실행되는 것을 방지하기 위해 또는 예를 cmd2들어 작성해야 합니다 .{ cmd1 | cmd2; } < file > file2(cmd1 | cmd2 > file2) < filefile2cmd1cmd2file

답변3

<file파이프의 끝에 배치하는 것은 cat file처음에 배치하는 것보다 읽기 어렵습니다. 자연스러운 영어는 왼쪽에서 오른쪽으로 읽습니다.

<file파이프의 시작 부분을 처음에 두는 것도 cat보다 가독성이 떨어진다고 말하고 싶습니다. 단어는 기호, 특히 잘못된 방향을 가리키는 것처럼 보이는 기호보다 더 읽기 쉽습니다.

cat보존된 서식을 사용합니다 command | command | command.

답변4

여기서 다른 답변이 직접적으로 해결하지 못하는 것 중 하나는 " cat불필요한 작업을 수행하는 고양이 프로세스를 생성"하기 때문에 "작동하지 않는 관련없는 고양이 프로세스를 생성"하기 때문에 이와 같이 사용하는 것이 "쓸모"가 아니라는 것입니다. " " 의미, 그것은 쓸모가 없습니다.

두 경우 모두:

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

쉘은 일부 파일 또는 표준 입력(각각)에서 읽는 sed 프로세스를 시작한 다음 일부 처리를 수행합니다. 개행 문자를 만날 때까지 읽고 줄의 첫 번째 "foo"를 "bar"(있는 경우)로 바꿉니다. 그런 다음 해당 행을 표준 출력으로 인쇄하고 반복하십시오.

다음의 경우:

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

쉘은 cat 프로세스와 sed 프로세스를 생성하고 cat의 표준 출력을 sed의 표준 입력에 연결합니다. cat 프로세스는 파일에서 킬로바이트 또는 메가바이트 단위의 청크를 읽고 이를 표준 출력에 씁니다. 위의 두 번째 예에서 볼 수 있듯이 sed sommand가 이를 가져옵니다. sed가 이 블록을 처리하는 동안 cat은 sed가 계속 진행할 수 있도록 다른 블록을 읽고 이를 표준 출력에 씁니다.

즉, 명령을 추가하는 데 필요한 추가 작업은 cat추가 프로세스를 생성하는 추가 작업뿐만 cat아니라 파일 바이트를 한 번이 아닌 두 번 읽고 쓰는 추가 작업이기도 합니다. 현실적으로 말하자면, 현대 시스템에서는 이것이 큰 차이를 가져오지 않습니다. 시스템이 몇 마이크로초 동안 불필요한 작업을 수행하게 할 수도 있습니다. 그러나 이미 성능이 부족한 컴퓨터에서 스크립트를 사용하는 사람들에게 스크립트를 배포하려는 경우 여러 반복을 통해 몇 마이크로초가 경과할 수 있습니다.

관련 정보