텍스트 파일에서 세그먼트를 추출하는 가장 좋은 방법은 무엇입니까?


답변:


12

당신은 시도 할 수 있습니다 :

cat textfile | head -n 45 | tail -n 26

또는

cat textfile | awk "20 <= NR && NR <= 45" 

최신 정보:

Mahomedalid가 지적했듯이 cat필요하지 않으며 약간 중복되지만 깨끗하고 읽기 쉬운 명령을 만듭니다.

경우 cat당신을 귀찮게하지, 더 나은 sollution은 다음과 같습니다

<textfile awk "20 <= NR && NR <= 45"

2
awk NR==20,NR==45 textfile작동하고 쉽게 읽을 수 있습니다.
ephemient

나는 stdin의 사용을 더 좋아한다. 그것은 나머지 nix와 일부 글로벌 일관성을 가지고있다
Stefan

1
커맨드 라인 인수를 읽으면 다른 UNIX 유틸리티와 일관성이 있으며, 주요 요점은 awk의 ,범위 연산자 를 보여주었습니다 .
ephemient

lol, 나는 @adam을 의미했다. 그러나 네, 당신의 제안을 좋아합니다
Stefan

@ephemient의 대답이 여기에 가장 좋은 것이라고 생각합니다. 그렇지 않으면 명령이 다소 암호입니다.
Léo Léopold Hertz 준영

13

더 간단합니다 :

sed -n '20,45p;45q' < textfile

-n 플래그는 기본 출력을 비활성화합니다. "20,45"는 20 ~ 45 행을 포함합니다. "p"명령은 현재 행을 인쇄합니다. 그리고 라인을 인쇄 한 후 q가 종료됩니다.


1
+1 nice, i like, 그러나 그 라인 20 ~ 45 :)
Stefan

1
좋아, 나는 그것을 20,45 :-)라고 편집했다
dkagedal

27169334 행 파일에서 단일 행 26995107을 추출 할 때 q명령 (에서 시작하는 모든 항목)을 제거하면 ;성능이 향상되었습니다.
Ruslan

6

이것은 답변이 아니지만 주석으로 게시 할 수 없습니다.

그것을 할 수있는 또 다른 (매우 빠르게) 방법이 제안되었다 mikeserv 여기 :

{ head -n 19 >/dev/null; head -n 26; } <infile

여기 와 동일한 테스트 파일과 동일한 절차를 사용하여 몇 가지 벤치 마크가 있습니다 (발췌 1000020-1000045).

mikeserv :

{ head -n 1000019 >/dev/null; head -n 26; } <iplist

real    0m0.059s

스테판 :

head iplist -n 1000045 | tail -n 26

real    0m0.054s

이것들은 지금까지 가장 빠른 솔루션이며 차이점은 무시할 수 있습니다 (단일 패스의 경우) (두 줄, 수백만 줄 등의 다른 범위로 시도했습니다).

그러나 파이프없이 파이프를 사용하면 다음 과 같이 비슷한 방식으로 여러 범위 의 라인 을 탐색해야하는 애플리케이션에 상당한 이점이 있습니다 .

for  pass in 0 1 2 3 4 5 6 7 8 9
do   printf "pass#$pass:\t"
     head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES

... 인쇄 ...

pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000

... 한 번만 파일을 읽습니다.


다른 sed/ awk/ perl솔루션은 전체 파일을 읽고 이것은 거대한 파일에 관한 것이므로 매우 효율적이지 않습니다. 나는 몇 가지 대안을 던졌다 그 exit또는 qUIT 지정된 범위의 마지막 줄 끝

스테판 :

awk "1000020 <= NR && NR <= 1000045" iplist

real    0m2.448s

vs.

awk "NR >= 1000020;NR==1000045{exit}" iplist

real    0m0.243s

dkagedal ( sed) :

sed -n 1000020,1000045p iplist

real    0m0.947s

vs.

sed '1,1000019d;1000045q' iplist

real    0m0.143s

스티븐 D :

perl -ne 'print if 1000020..1000045' iplist

real    0m2.041s

vs.

perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist

real    0m0.369s

+1 이것이 가장 좋은 대답이라고 생각합니다! awk NR==1000020,NR==1000045 textfile시스템에서 시간이 얼마나 걸리는지를 알게되면 좋을 것 입니다.
Léo Léopold Hertz 준영

3
ruby -ne 'print if 20 .. 45' file

1
동료 루비 스트 여러분, 투표권을 얻습니다
Stefan

1
우리가 그 동안 왜 안 python -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'그래? :-P 이것은 awk / sed에서 영감을 얻은 Perl을 모델로 한 루비가 쉽게 할 수있는 일입니다.
ephemient

2

sed와 awk가 이미 취해 졌으므로 여기에 perl 솔루션이 있습니다.

perl -nle "print if ($. > 19 && $. < 46)" < textfile

또는 의견에서 지적한 바와 같이 :

perl -ne 'print if 20..45' textfile

2
모든 추가 문자는 무엇입니까? 줄 바꿈을 제거하고 다시 추가 할 필요가없고 플립 플롭은 줄 번호와의 비교를 가정하며 다이아몬드 연산자는 제공된 경우 인수를 통해 실행됩니다. perl -ne'print if 20..45' textfile
ephemient

1
좋은. -nle은 내가 생각하는 약간의 반사입니다. 나머지에 관해서는, 나는 무지를 구할 변명이 없습니다.
Steven D
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.