정렬하지만 헤더 행을 맨 위에 유지


55

먼저 열 머리글 인 한 줄을 생성 한 다음 한 줄의 데이터를 생성하는 프로그램에서 출력을 얻습니다. 이 출력의 다양한 열을 잘라 내고 다양한 열에 따라 정렬하여보고 싶습니다. 헤더가 없으면 절단 및 정렬은 열의 하위 집합과 함께 또는 열의 -k옵션을 통해 쉽게 수행 할 수 있습니다. 그러나이 정렬 방법은 열 머리글을 나머지 출력 행과 혼합합니다. 헤더를 맨 위에 유지하는 쉬운 방법이 있습니까?sortcutawk


1
나는 다음 링크를 발견했다 . 그러나이 기술 { head -1; sort; }을 작동 시킬 수는 없습니다 . 항상 첫 줄 다음에 많은 텍스트를 삭제합니다. 왜 이런 일이 발생하는지 알고 있습니까?
jonderry

1
나는 그것 때문에 의심 head버퍼에 하나 개 이상의 라인을 읽고 멀리 그것의 대부분을 던지고있다. 내 sed생각은 같은 문제가 있었다.
Andy

@ jonderry-이 기술은 lseek가능한 입력 에서만 작동 하므로 파이프에서 읽을 때 작동하지 않습니다. 파일로 리디렉션 >outfile한 다음 실행 하면 작동 합니다.{ head -n 1; sort; } <outfile
don_crissti

답변:


58

Andy의 아이디어를 훔쳐서 사용하기 쉽도록하기

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

이제 할 수 있습니다 :

$ ps -o pid,comm | body sort -k2
  PID COMMAND
24759 bash
31276 bash
31032 less
31177 less
31020 man
31167 man
...

$ ps -o pid,comm | body grep less
  PID COMMAND
31032 less
31177 less

ps -C COMMAND보다 적합 할 수도 grep COMMAND있지만 이는 단지 예일뿐입니다. 또한와 -C같은 다른 선택 옵션을 사용한 경우 에는 사용할 수 없습니다 -U.
Mikel

아니면 전화해야 body합니까? body sort또는 에서 와 같이 body grep. 생각?
Mikel

3
본문에서 작업을 수행하고 있기 때문에 에서 (으) header로 이름이 변경되었습니다 body. 잘하면 그것은 더 의미가 있습니다.
Mikel

2
body모든 후속 파이프 라인 참가자 를 불러야 합니다.ps -o pid,comm | body grep less | body sort -k1nr
주교

1
@Tim <foo body sort -k2또는을 쓸 수 있습니다 body sort -k2 <foo. 당신이 원하는 것에서 하나의 추가 캐릭터.
Mikel

36

bash를 사용하여 헤더를 맨 위에 유지할 수 있습니다.

command | (read -r; printf "%s\n" "$REPLY"; sort)

아니면 펄로하세요 :

command | perl -e 'print scalar (<>); print sort { ... } <>'

2
+1 최고 내가 생각하는 쉘 함수로 묶을 가치가있다.
Mikel

1
1, 서브 쉘이 바람직하다, 또는 왜 어떤 이유로 {}대신 좋아 ()?
jonderry

2
IFS=입력을 읽을 때 단어 분할을 비활성화합니다. 에 읽을 때 필요하다고 생각하지 않습니다 $REPLY. 설정된 echo경우 백 슬래시 이스케이프를 확장 xpg_echo합니다 (기본값이 아님). printf이 경우 더 안전합니다. echo $REPLY따옴표가 없으면 공백이 압축됩니다. echo "$REPLY"괜찮을 것 같아요 . read -r입력에 백 슬래시 이스케이프가 포함 된 경우 필요합니다. 이 중 일부는 bash 버전에 따라 달라질 수 있습니다.
Andy

1
@ 앤디 : 와우, 당신은 read REPLY; echo $REPLY(앞의 공백을 제거하고) read; echo $REPLY하지 않는 다른 규칙입니다 .
Mikel

1
@Andy : IIRC의 기본값 xpg_echo은 시스템 에 따라 다릅니다 (예 : Solaris). 기본값이 true라고 생각합니다. 이것이 Gilles가 printf그토록 많은 것을 좋아하는 이유입니다 . 그것은 예측 가능한 행동을하는 유일한 것입니다.
Mikel

23

스크립트에서 잘 작동 하는 멋진 awk 버전 을 찾았 습니다 .

awk 'NR == 1; NR > 1 {print $0 | "sort -n"}'

1
나는 이것을 좋아하지만 약간의 설명이 필요하다-파이프는 awk 스크립트 안에있다. 어떻게 작동합니까? sort명령을 외부에서 호출 합니까? 누구나 awk 내에서 파이프 사용을 설명하는 페이지에 대한 링크를 알고 있습니까?
와일드 카드

@Wildcard 공식 매뉴얼 페이지 또는 이 입문서를 확인할 수 있습니다 .
lapo

4

해 키지 만 효과적 임 : 정렬하기 전에 0모든 헤더 행과 1다른 모든 행 앞에 추가하십시오 . 정렬 후 첫 번째 문자를 제거하십시오.

… |
awk '{print (NR <= 2 ? "0 " : "1 ") $0}' |
sort -k 1 -k… |
cut -b 3-

3

다음은 출력을 파이프하여 모든 것을 정렬하지만 첫 번째 줄은 맨 위에 두는 마술 펄 라인 노이즈입니다. perl -e 'print scalar <>, sort <>;'


2

나는 command | {head -1; sort; }해결책을 시험해 보았고 실제로 나사를 조이는 것을 확인할 수 있었다 - head파이프에서 여러 줄을 읽은 다음 첫 번째 것을 출력한다. 따라서 읽지 head 않은sort 나머지 출력은 라인 2에서 시작하여 나머지 출력으로 전달 되지 않습니다 !

결과는 명령 출력의 시작 부분에있는 줄 (및 한 줄)이 누락 된 것입니다 (여전히 첫 번째 줄을 제외하고)- wc끝에 파이프를 추가하여 쉽게 확인할 수 있습니다. 위의 파이프 라인-이것을 모르면 추적하기가 매우 어렵습니다! 나는 출력을 풀기 전에 출력에 부분 라인 (처음 100 바이트 정도)이있는 이유를 해결하기 위해 적어도 20 분을 보냈습니다.

내가 아름답게 일했고 명령을 두 번 실행할 필요가없는 결과는 다음과 같습니다.

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile
sed 1d $myfile | sort

rm $myfile

출력을 파일에 넣어야하는 경우이를 다음과 같이 수정할 수 있습니다.

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile > outputfile
sed 1d $myfile | sort >> outputfile

rm $myfile

당신이 경우 ksh93의 사용할 수있는 head내장 또는 line(여전히 하나를 가지고 시스템) 유틸리티 나 gnu-sed -u q또는 IFS=read -r line; printf '%s\n' "$line"이를 방지하기 위해 한 번에 입력 한 바이트를 읽고.
Stéphane Chazelas

1

나는 이것이 가장 쉽다고 생각한다.

ps -ef | ( head -n 1 ; sort )

또는 이것은 서브 쉘을 만들지 않기 때문에 아마도 더 빠릅니다.

ps -ef | { head -n 1 ; sort ; }

다른 멋진 용도

헤더 행 뒤의 셔플 라인

cat file.txt |  ( head -n 1 ; shuf )

헤더 행 뒤의 역행

cat file.txt |  ( head -n 1 ; tac )

2
unix.stackexchange.com/questions/11856/…을 참조하십시오 . 이것은 실제로 좋은 해결책이 아닙니다.
와일드 카드

1
작동하지 않고 cat file | { head -n 1 ; sort ; } > file2헤드 만 표시
Peter Krauss

0
command | head -1; command | tail -n +2 | sort

4
이것은 command두 번 시작됩니다 . 따라서 일부 특정 명령으로 제한됩니다. 그러나 ps예제에서 요청 된 명령의 경우 작동합니다.
jofel

0

간단하고 간단합니다!

<command> | head -n 1; <command> | sed 1d | sort <....>
  • sed nd ---> 'n'은 줄 번호를 지정하고 'd'는 삭제를 나타냅니다.

1
조펠이 1 년 반 전에 Sarva의 답변에 대해 언급 한 것처럼, 이것은 command두 번 시작 됩니다. 따라서 파이프 라인에 사용하기에는 적합하지 않습니다.
와일드 카드

0

나는 명령에 대한 해결책을 찾기 위해 여기에왔다 w. 이 명령은 로그인 한 사람과 수행중인 작업의 세부 사항을 표시합니다.

결과를 정렬하여 표시하지만 머리글을 맨 위에두면 (두 줄의 머리글이 있음) 다음과 같이 설정했습니다.

w | head -n 2; w | tail -n +3 | sort

분명히 이것은 명령을 w두 번 실행 하므로 모든 상황에 적합하지 않을 수 있습니다. 그러나 그 장점으로 인해 기억하기가 훨씬 쉽습니다.

tail -n +3'세 번째부터 모든 줄 표시' 라는 의미에 유의 하십시오 ( man tail자세한 내용 참조).


-2

시도해보십시오 :

wc -l file_name | tail -n $(awk '{print $1-1}') file_name | sort

3
나는 그것을 얻지 못한다
Pierre.Vriens
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.