[unix] 파일의 처음 몇 줄과 마지막 몇 줄을 표시하는 명령

행이 많은 파일이 있고 각 행에는 시작과 같이 타임 스탬프가 있습니다.

[Thread-3] (21/09/12 06:17:38:672) logged message from code.....

따라서이 로그 파일에서 자주 2 가지를 확인합니다.

  1. 전역 조건과 시작 시간이있는 처음 몇 개의 행도 제공됩니다.
  2. 마지막 정보는 다른 정보와 함께 종료 상태입니다.

파일의 처음과 마지막 몇 줄만 표시 할 수있는 빠르고 편리한 단일 명령이 있습니까?



답변

하나의 명령으로 sed또는 awk을 사용 하여 만들 수 있습니다 . 그러나 속도가 느슨해 져서 원인이 sed되어 awk어쨌든 전체 파일을 실행해야합니다. 속도 관점에서 볼 때마다 tail+ 를 조합하여 기능을 사용하는 것이 훨씬 좋습니다 head. 입력이 파이프 인 경우 작동하지 않는 단점이 있지만 쉘이 지원하는 경우 프로세스 대체를 사용할 수 있습니다 (아래 예 참조).

first_last () {
    head -n 10 -- "$1"
    tail -n 10 -- "$1"
}

그냥 시작으로

first_last "/path/to/file_to_process"

프로세스 대체를 진행하려면 (bash, zsh, ksh와 같은 쉘만 해당) :

first_last <( command )

추신. grep“전역 조건”이 존재하는지 확인 하기 위해를 추가 할 수도 있습니다 .


답변

@rush는 head + tail을 사용하면 큰 파일에 더 효율적이지만 작은 파일 (<20 줄)의 경우 일부 줄이 두 번 출력 될 수 있습니다.

{ head; tail;} < /path/to/file

똑같이 효율적이지만 위의 문제는 없습니다.


답변

{ head; tail; }솔루션은 파이프 (또는 소켓 또는 사용 할 수없는 다른 파일)에서 작동 head하지 않습니다. 블록으로 읽을 때 너무 많은 데이터를 소비하고 파이프에서 다시 커서를 검색 할 수 없기 때문에 tail의미 하는 것 이상으로 커서를 파일 안에 남겨 둘 수 없기 때문 입니다 선택합니다.

따라서 쉘과 같이 한 번에 한 문자 씩 읽는 도구를 사용할 수 있습니다 read(여기서는 헤드 라인과 테일 라인의 수를 인수로 사용하는 함수 사용).

head_tail() {
  n=0
  while [ "$n" -lt "$1" ]; do
    IFS= read -r line || { printf %s "$line"; break; }
    printf '%s\n' "$line"
    n=$(($n + 1))
  done
  tail -n "${2-$1}"
}
seq 100 | head_tail 5 10
seq 20 | head_tail 5

또는 tailawk에서 예를 들어 다음과 같이 구현하십시오 .

head_tail() {
  awk -v h="$1" -v t="${2-$1}" '
    {l[NR%t]=$0}
    NR<=h
    END{
      n=NR-t+1
      if(n <= h) n = h+1
      for (;n<=NR;n++) print l[n%t]
    }'
}

sed:

head_tail() {
  sed -e "1,${1}b" -e :1 -e "$(($1+${2-$1})),\$!{N;b1" -e '}' -e 'N;D'
}

(일부 sed구현에서는 패턴 공간의 크기에 대한 제한이 낮으므로 테일 라인 수의 큰 값에는 실패합니다).


답변

bash프로세스 대체를 사용 하여 다음을 수행 할 수 있습니다.

make_some_output | tee >(tail -n 2) >(head -n 2; cat >/dev/null) >/dev/null

줄이 순서대로 보장되지는 않지만 약 8kB보다 긴 파일의 경우에는 그럴 가능성이 높습니다. 이 8kB 컷오프는 읽기 버퍼의 일반적인 크기이며 | {head; tail;}작은 파일에서는 작동하지 않는 이유와 관련이 있습니다.

cat >/dev/null킵 할 필요가 head살아 파이프 라인을. 그렇지 않으면 tee일찍 종료되고에서 출력을 얻는 동안 tail입력이 아닌 중간 부분에서 출력됩니다.

마지막으로 왜 >/dev/null대신에 tail다른 곳으로 옮기는가 |? 다음과 같은 경우 :

make_some_output | tee >(head -n 2; cat >/dev/null) | tail -n 2  # doesn't work

headstdout은 tail콘솔 이 아닌 파이프로 파이프에 공급되며 이는 우리가 원하는 것이 아닙니다.


답변

사용 ed(하지만 전체 파일을 RAM으로 읽습니다) :

# cf. http://wiki.bash-hackers.org/howto/edit-ed
printf '%s\n' 'H' '1,10p' '$-10,$p' 'q' | ed -s file


답변

인수를 사용할 수 있도록 Stephane의 첫 번째 솔루션 (본느 또는 POSIX 셸에서 작동) :

head_tail() {
    head "$@";
    tail "$@";
}

이제 당신은 이것을 할 수 있습니다 :

head_tail -n 5 < /path/to/file

물론 이것은 하나의 파일 만보 고 Stephane의 솔루션과 마찬가지로 일반 (찾을 수있는) 파일에서만 작동한다고 가정합니다.


답변

GNU 의 -u( --unbuffered) 옵션을 sed사용 sed -u 2q하면 다음에 대한 버퍼되지 않은 대안으로 사용할 수 있습니다 head -n2.

$ seq 100|(sed -u 2q;tail -n2)
1
2
99
100

(head -n2;tail -n2)마지막 행이 head다음에 의해 소비되는 입력 블록의 일부인 경우 실패합니다 .

$ seq 1000|(head -n2;tail -n2)
1
2
999
1000
$ seq 100|(head -n2;tail -n2)
1
2