유닉스-파일의 머리와 꼬리


131

txt 파일이 있다고 가정하면 파일의 상위 10 줄과 아래쪽 10 줄을 동시에 보는 명령은 무엇입니까?

즉, 파일 길이가 200 줄이면 1-10 행과 190-200 행을 한 번에 봅니다.


"한 번에"무엇을 의미합니까?
cnicutar

@cnicutar 즉. -10 파일로 이동하지 않고 데이터를보고 나서 별도로 -10 파일 로 이동하여 데이터를보고
toop

@toop 실제 작업 예제를 원하면 stackoverflow.com/a/44849814/99834
sorin

답변:


208

간단하게 할 수 있습니다 :

(head; tail) < file.txt

그리고 어떤 이유로 파이프를 사용해야하는 경우 다음과 같이하십시오.

cat file.txt | (head; tail)

참고 : file.txt의 줄 수가 head의 기본 줄 + tail의 기본 줄보다 작 으면 중복 된 줄이 인쇄됩니다.


54
엄밀히 말하면, 이것은 원본 파일의 꼬리를 제공하지 않지만 이후의 스트림 꼬리는 파일 head의 처음 10 줄을 소비했습니다. ( head < file.txt; tail < file.txt20 줄 미만의 파일에서 이것을 비교하십시오 ). 명심해야 할 사소한 점입니다. (그러나 여전히 +1)
chepner

15
좋은. 머리 부분과 꼬리 부분 사이에 간격이 필요한 경우 : (head; echo; tail) <file.txt
Simon Hibbs

3
왜 / 어떻게 작동하는지 궁금합니다. 새로운 질문으로 물었습니다 : stackoverflow.com/questions/13718242
zellyn

9
@nametal 사실, 당신은 그렇게 많이 얻지 못할 수도 있습니다. 입력의 처음 10 개 라인 head표시 하지만 10 번째 라인 끝을 찾기 위해 더 많은 소비를 하지 않았다는 보장은 없으며 , 입력에 대한 입력을 less줄입니다.
chepner

20
유감스럽게도 대답은 일부 경우에만 작동합니다. seq 100 | (head; tail)처음 10 개의 숫자 만 제공합니다. 더 큰 입력 크기 (예 :)에서만 seq 2000꼬리가 입력을받습니다.
모듈 식

18

ed 입니다 standard text editor

$ echo -e '1+10,$-10d\n%p' | ed -s file.txt

2
파일에 200 줄 이상이 있으면 어떻게됩니까? 그리고 당신은 라인의 숫자를 몰라요?
Paul

@Paul 나는 다음으로 변경 sed했다ed
kev

14

순수 스트림 (예 : 명령 출력)의 경우 'tee'를 사용하여 스트림을 분기하고 하나의 스트림을 머리에, 하나의 스트림을 머리에 보냅니다. 이를 위해서는 bash (+ / dev / fd / N)의 '> (list)'기능을 사용해야합니다.

( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )

또는 복잡한 리디렉션이있는 / dev / fd / N (또는 / dev / stderr) 및 서브 쉘 사용 :

( ( seq 1 100 | tee /dev/fd/2 | head 1>&3 ) 2>&1 | tail ) 3>&1
( ( seq 1 100 | tee /dev/stderr | head 1>&3 ) 2>&1 | tail ) 3>&1

(이들 중 어느 것도 csh 또는 tcsh에서 작동하지 않습니다.)

약간 더 나은 제어 기능을 갖춘 무언가를 위해 다음 perl 명령을 사용할 수 있습니다.

COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'

1
스트림 지원 +1 stderr를 재사용 할 수 있습니다 :COMMAND | { tee >(head >&2) | tail; } |& other_commands
jfs

2
btw, 버퍼 크기보다 큰 파일 (시스템의 8K)이 끊어집니다. cat >/dev/null수정 :COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
jfs

나는 해결책을 사랑하지만, AA에 대한 재생 후 나는 꼬리가 머리를하기 전에 실행중인 경우에 ... 더 사이에 순서가 보장되는 것으로 나타났습니다없는 상태 headtail명령 : \ ...

7
(sed -u 10q; echo ...; tail) < file.txt

(head;tail)테마의 또 다른 변형 이지만 작은 파일의 초기 버퍼 채우기 문제를 피하십시오.


4

head -10 file.txt; tail -10 file.txt

그 외에는 자신의 프로그램 / 스크립트를 작성해야합니다.


1
니스, 난 항상 사용했습니다 cathead또는 tail내가 개별적으로 사용할 수 있다는 것을 알고, 좋은 파이프!
Paul

그런 다음 처음 10 + 마지막 10을 다른 명령으로 파이프하는 방법은 무엇입니까?
toop December

1
@ 폴 -와 'your_program'은 10 대신 20를 반환 화장실 -l로
toop

3
하부 쉘 산란하지 않고 또는 : { head file; tail file; } | prog(필요한 괄호 안에 간격 및 후행 세미콜론)
글렌 잭맨

1
와우 ... 거의 2 년 후 다른 사람들과 상당히 유사한 답변을 얻은 다운 투표 (왜 투표하지 않은 이유를 게시하지 않기로 선택한 사람). 좋은!
mah

4

JF Sebastian의 의견을 바탕으로 :

cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1

이 방법으로 첫 번째 라인과 나머지 라인을 하나의 파이프에서 다르게 처리 할 수 ​​있으며 이는 CSV 데이터 작업에 유용합니다.

{ echo N; seq 3;} | { tee >(head -n1 | sed 's/$/*2/' >&3; cat >/dev/null) | tail -n+2 | awk '{print $1*2}'; } 3>&1
N * 2
2
4
6

3

여기서 문제는 스트림 지향 프로그램이 파일의 길이를 미리 알지 못한다는 것입니다 (실제 스트림 인 경우 파일 길이가 없기 때문에).

같은 도구 tail 다음 인쇄 본 마지막 n 라인을 버퍼 및 스트림의 마지막 기다립니다.

단일 명령 으로이 작업을 수행하려면 (오프셋으로 작동하고 겹치는 경우 줄을 반복하지 않도록) 언급 한이 동작을 에뮬레이트해야합니다.

이 awk를보십시오 :

awk -v offset=10 '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' yourfile

오프셋이 파일보다 클 때 문제를 피하려면 더 많은 작업이 필요합니다
Samus_

예, 이것은 파일뿐만 아니라 파이프 출력에서도 작동합니다. a.out | awk -v ...
Camille Goudeseune

실제로 :) 그러나 그것은 awk의 정상적인 행동이지만, 대부분의 명령 줄 프로그램은 인수없이 호출 될 때 stdin에서 작동합니다.
Samus_

1
원하는 동작에 매우 가깝지만 <10 줄의 경우 새 줄이 추가됩니다.
sorin

3

이 솔루션으로 끝나는 데 많은 시간이 걸렸으며 지금까지 모든 사용 사례를 다루는 유일한 솔루션 인 것 같습니다.

command | tee full.log | stdbuf -i0 -o0 -e0 awk -v offset=${MAX_LINES:-200} \
          '{
               if (NR <= offset) print;
               else {
                   a[NR] = $0;
                   delete a[NR-offset];
                   printf "." > "/dev/stderr"
                   }
           }
           END {
             print "" > "/dev/stderr";
             for(i=NR-offset+1 > offset ? NR-offset+1: offset+1 ;i<=NR;i++)
             { print a[i]}
           }'

기능 목록 :

  • 헤드의 라이브 출력 (확실히 테일의 경우 불가능)
  • 외부 파일을 사용하지 않음
  • MAX_LINES 다음에 각 줄에 대해 진행률 표시 줄 1 점으로 장시간 실행되는 작업에 매우 유용합니다.
  • stderr의 진행률 표시 줄, 진행률 점이 머리 + 꼬리와 분리되어 있는지 확인하십시오 (stdout을 파이프하려는 경우 매우 편리합니다)
  • 버퍼링으로 인해 발생 가능한 잘못된 로깅 순서를 피합니다 (stdbuf)
  • 총 라인 수가 head + tail보다 작을 때는 중복 된 출력을 피하십시오.

2

나는이 솔루션을 잠시 동안 찾고있다. sed로 직접 시도했지만 파일 / 스트림의 길이를 미리 알지 못하는 문제는 극복 할 수 없었습니다. 위에서 사용 가능한 모든 옵션 중에서 Camille Goudeseune의 awk 솔루션이 마음에 듭니다. 그는 솔루션이 충분히 작은 데이터 세트로 출력에 여분의 빈 줄을 남겼 음을 기록했습니다. 여기에 여분의 라인을 제거하는 솔루션의 수정 사항이 있습니다.

headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { a_count=0; for (i in a) {a_count++}; for (i=NR-a_count+1; i<=NR; i++) print a[i] }' ; }

1

글쎄, 당신은 항상 그들을 함께 연결할 수 있습니다. 이와 같이 head fiename_foo && tail filename_foo. 충분하지 않으면 .profile 파일 또는 사용하는 로그인 파일에 bash 함수를 직접 작성할 수 있습니다.

head_and_tail() {
    head $1 && tail $1
}

그리고 나중에 쉘 프롬프트에서 호출하십시오 head_and_tail filename_foo.


1

file.ext의 처음 10 행, 마지막 10 행 :

cat file.ext | head -10 && cat file.ext | tail -10

파일의 마지막 10 줄, 첫 10 줄 :

cat file.ext | tail -10 && cat file.ext | head -10

그런 다음 다른 곳에서도 출력을 파이프 할 수 있습니다.

(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program


5
head -10 file.txt를 호출 할 때 왜 cat을 사용합니까?
jstarek

줄 수를 가변으로 만들 수 있으므로 호출은 다음과 같습니다. head_ tail (foo, m, n)-텍스트의 첫 번째 snd 마지막 n 줄을 반환합니까?
리카르도

3 개 인수를 받아에게 전달하는 bash는 스크립트 작성 포함 할 것을 @ricardo tailhead별칭 - 보내고 그것을 또는 기능을.
Paul


1

위의 아이디어를 그리기 (bash 및 zsh 테스트)

별명 '모자'머리와 꼬리를 사용하여

alias hat='(head -5 && echo "^^^------vvv" && tail -5) < '


hat large.sql

0

sed이 작업 에 사용하지 않는 이유는 무엇 입니까?

sed -n -e 1,+9p -e 190,+9p textfile.txt


3
알려진 길이의 파일에는 작동하지만 길이를 알 수없는 파일에는 적용되지 않습니다.
케빈

0

파일뿐만 아니라 파이프 (스트림)를 처리하려면 .bashrc 또는 .profile 파일에 추가하십시오.

headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' ; }

그럼 당신은 할 수 없습니다

headtail 10 < file.txt

뿐만 아니라

a.out | headtail 10

(이것은 평범한 이전과 달리 10이 입력 길이를 초과 할 때 가짜 빈 줄을 계속 추가합니다. a.out | (head; tail) 합니다. 이전 답변자에게 감사합니다.)

참고 : headtail 10아닙니다 headtail -10.


0

@Samus_ 설명 무엇을 구축 여기 방법 @Aleksandra Zalcman의 명령이 작동에 대해,이 변화는 꼬리 계수 선없이 시작되는 위치를 빠르게 발견 할 수 없을 때 편리합니다.

{ head; echo "####################\n...\n####################"; tail; } < file.txt

또는 20 줄 이외의 다른 작업을 시작하면 줄 수가 도움이 될 수도 있습니다.

{ head -n 18; tail -n 14; } < file.txt | cat -n

0

파일의 처음 10 행과 마지막 10 행을 인쇄하려면 다음을 시도하십시오.

cat <(head -n10 file.txt) <(tail -n10 file.txt) | less


0
sed -n "1,10p; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"

참고 : aFile 변수에는 파일의 전체 경로가 포함 됩니다.


0

파일 크기에 따라 내용을 적극적으로 읽는 것이 바람직하지 않을 수 있습니다. 그런 상황에서 간단한 쉘 스크립팅으로 충분하다고 생각합니다.

최근에 내가 분석하고있는 많은 대용량 CSV 파일에 대해 이것을 처리 한 방법은 다음과 같습니다.

$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done

그러면 각 파일의 처음 10 줄과 마지막 10 줄이 인쇄되고 파일 이름과 줄임표가 앞뒤에 인쇄됩니다.

하나의 큰 파일의 경우 동일한 효과를 위해 다음을 실행할 수 있습니다.

$ head somefile.csv && echo ... && tail somefile.csv

0

stdin을 소비하지만 단순하며 99 %의 사용 사례에서 작동

head_and_tail

#!/usr/bin/env bash
COUNT=${1:-10}
IT=$(cat /dev/stdin)
echo "$IT" | head -n$COUNT
echo "..."
echo "$IT" | tail -n$COUNT

$ seq 100 | head_and_tail 4
1
2
3
4
...
97
98
99
100
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.