여러 줄이 있는 파일이 있는데 각 줄의 시작 부분에 타임스탬프가 있습니다.
[Thread-3] (21/09/12 06:17:38:672) logged message from code.....
그래서 제가 항상 이 로그 파일에서 확인하는 것이 두 가지 있습니다.
- 처음 몇 줄에는 전역 조건이 있으며 시작 시간도 제공됩니다.
- 마지막 몇 줄에는 종료 상태와 기타 정보가 포함되어 있습니다.
파일의 첫 번째 줄과 마지막 줄만 표시할 수 있는 빠르고 편리한 단일 명령이 있습니까?
답변1
@rush는 큰 파일의 경우 head + tail을 사용하는 것이 옳지만 작은 파일(20줄 미만)의 경우 일부 줄이 두 번 출력될 수 있습니다.
{ head; tail;} < /path/to/file
마찬가지로 잘 작동하지만 위의 문제는 없습니다.
답변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
PS "전역 조건"이 존재하는지 확인하기 위해 하나를 추가할 수도 있습니다 .
답변3
이 솔루션은 청크 단위로 읽을 때 너무 많은 데이터를 소비할 수 있고 파이프에서 검색할 수 없으면 커서가 범위를 벗어날 수 있으므로 { head; tail; }
파이프(또는 소켓 또는 기타 검색할 수 없는 파일)에서는 작동하지 않습니다. head
file 그 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
또는 awk로 구현하세요 tail
. 예를 들면 다음과 같습니다.
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
구현에서는 패턴 공간의 크기에 대한 제한이 낮으므로 후행 줄의 값이 더 크면 실패합니다.)
답변4
프로세스 대체를 사용하면 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
head
tail
표준 출력은 콘솔 대신 파이프로 이동하는데 , 이는 우리가 전혀 원하는 것이 아닙니다.