파일에서 n 번째 줄을 가져 오는 배쉬 도구


604

그렇게하는 "정식적인"방법이 있습니까? 나는 사용하고있다head -n | tail -1 트릭을 수행하는 것을 했지만 파일에서 한 줄 또는 여러 줄을 추출하는 Bash 도구가 있는지 궁금합니다.

"정규"라는 말은 주요 기능을 수행하는 프로그램을 의미합니다.


10
"유닉스 방식"은 각자의 업무를 잘 수행하는 툴을 연결하는 것입니다. 그래서 나는 당신이 이미 매우 적합한 방법을 찾았다 고 생각합니다. 다른 방법은 다음과 같습니다 awksed나는 누군가가 그렇게뿐만 아니라 펄 한 줄을 마련하거나 할 수 있습니다 확신)
0xC0000022L

3
이중 명령은 head | tail솔루션이 차선 책임을 제안합니다 . 다른 거의 최적의 솔루션이 제안되었습니다.
Jonathan Leffler

평균적인 경우에 어떤 솔루션이 가장 빠른 벤치 마크를 실행 했습니까?
Marcin

5
Catx X에서 Y 행 까지의 벤치 마크 ( 유닉스 용)Unix & Linux 의 거대한 파일 에 있습니다. (cc @Marcin, 2 년 이상 계속 궁금한 경우)
Kevin

6
head | tail은 입력에 존재하지 않는 행을 조회 할 경우 솔루션은 작업을하지 않습니다 : 그것은 마지막 줄을 인쇄합니다.
jarno

답변:


801

head파이프가 tail큰 파일의 경우 속도가 느립니다. 나는 이렇게 제안 할 것이다 sed:

sed 'NUMq;d' file

NUM인쇄하려는 줄 번호는 어디에 있습니까 ? 예를 들어, sed '10q;d' file10 번째 줄을 인쇄하려면file .

설명:

NUMq줄 번호가이면 즉시 종료됩니다 NUM.

d인쇄하는 대신 줄을 삭제합니다. 종료시 q스크립트의 나머지 부분을 건너 뛰기 때문에 마지막 행에서 금지됩니다 .

NUM변수 가 있는 경우 작은 따옴표 대신 큰 따옴표를 사용하려고합니다.

sed "${NUM}q;d" file

44
궁금 사람들을 위해,이 솔루션은 9-6에 대한 배 빠른 이상의 보인다 sed -n 'NUMp'sed 'NUM!d'솔루션은 아래에 제안했다.
Skippy le Grand Gourou

75
나는 tail -n+NUM file | head -n1빠르거나 빠를 것 같다. 적어도 50 만 줄의 파일에서 NUM이 250000 인 파일을 시도했을 때 시스템에서 (상당히) 빠릅니다. YMMV,하지만 왜 그런지 모르겠습니다.
rici

2
@rici (이전 의견 수정) Linux (Ubuntu 12.04, Fedora 20) 에서 파일이 아직 캐시되지 않은 경우에만 사용 속도cat빨라집니다 (거의 두 배 빠름) . 파일이 캐시되면 filename 인수를 직접 사용하는 것이 더 빠르며 (약 1/3 더 빠름) 성능은 동일하게 유지됩니다. 흥미롭게도 OS X 10.9.3 에서는 / no , 파일 캐시 여부에 차이가 없는 것으로 보입니다 . @anubhava : 내 기쁨. catcatcat
mklement0

2
@SkippyleGrandGourou : 이 최적화특정 특성을 고려할 때, 숫자 범위 조차도 일반적인 진술로 의미가 없습니다 . 단 일반 테이크 아웃 이있다 : (a)이 최적화 안전하게 모든 입력에인가 될 수 있고, (b)에 효과가 없음에서 극적인 범위이다 행의 인덱스에 따라 전체 행의 개수를 기준으로 찾았다.
mklement0

17
sed 'NUMq첫 번째 NUM파일 을 출력 하고 ;d마지막 줄을 제외한 모든 파일 을 삭제합니다.
anubhava

304
sed -n '2p' < file.txt

두 번째 줄을 인쇄합니다

sed -n '2011p' < file.txt

2011 년 라인

sed -n '10,33p' < file.txt

10 행-33 행

sed -n '1p;3p' < file.txt

첫 번째와 세 번째 줄

등등...

sed로 줄을 추가하려면 다음을 확인하십시오.

sed : 특정 위치에 선을 삽입하십시오


6
<이 경우 @RafaelBarbosa는 필요하지 않습니다. 간단히 말해 sed -n '100p' < <(some_command)보편적 인 구문 :) 과 같은 리디렉션을 자주 사용했기 때문에 리디렉션을 사용하는 것이 좋습니다. 그것은 자신을 분기 할 때 리디렉션 쉘 수행되기 때문에, 그래서 ... 그것은 ... 단지 선호 (그리고 예, 그것은 하나 개의 문자 이상) : 덜 효과적이지
jm666

1
@ jm666 실제로 <:)를 사용하지 않은 경우 하나의 공백 대신에 '<'와 여분의 공백을 추가하기 때문에 일반적으로 2 자 이상입니다. <:)
rasen58

2
@ rasen58 공간도 캐릭터입니까? :) / 좋아요, 농담-맞아요 / :)
jm666

1
물론 누군가가 최적화를 수행 해야하는 경우 @duhaime. 그러나 "일반적인"문제에 대한 IMHO는 괜찮으며 그 차이는 눈에 띄지 않습니다. 또한 head/ tailsed -n '1p;3p'시나리오를 해결하지 못합니다 -더 많은 비 인접 행을 인쇄합니다 ...
jm666

1
물론 @duhaime-메모가 정확하고 필요합니다. :)
jm666

93

이 페이지에서 제안한 솔루션을 벤치마킹 할 수있는 독특한 상황이 있으므로이 답변을 각 솔루션에 대한 런타임이 포함 된 제안 솔루션의 통합으로 작성하고 있습니다.

설정

행당 하나의 키-값 쌍을 가진 3.261 기가 바이트 ASCII 텍스트 데이터 파일이 있습니다. 파일에는 총 3,339,550,320 행이 포함되어 있으며 Vim으로 이동하는 것을 포함하여 시도한 모든 편집기에서 열리지 않습니다. 발견 한 일부 값을 조사하려면 ~ 500,000,000 행 정도에서 시작해야합니다.

파일에 행이 너무 많기 때문에 :

  • 데이터에 유용한 작업을 수행하려면 행의 하위 집합 만 추출하면됩니다.
  • 내가 관심을 갖는 가치로 이어지는 모든 행을 읽는 데는 오랜 시간이 걸릴 것입니다.
  • 솔루션이 내가 관심있는 행을지나 읽고 나머지 파일을 계속 읽는 경우 거의 30 억 개의 관련 행을 읽는 데 시간을 낭비하고 필요한 것보다 6 배 더 오래 걸립니다.

가장 좋은 시나리오는 파일의 다른 행을 읽지 않고 파일에서 한 줄만 추출하는 솔루션이지만 Bash 에서이 작업을 수행하는 방법을 생각할 수 없습니다.

내 정신 건강을 위해 나는 내 자신의 문제에 필요한 500,000,000 줄 전체를 읽으려고하지 않을 것입니다. 대신 3,339,550,320에서 50,000,000 행을 추출하려고 시도합니다 (전체 파일을 읽는 데 필요한 시간보다 60 배 더 오래 걸립니다).

time내장 명령을 사용하여 각 명령을 벤치마킹 할 것입니다.

베이스 라인

먼저 head tail솔루션이 어떻게 작동하는지 봅시다 :

$ time head -50000000 myfile.ascii | tail -1
pgm_icnt = 0

real    1m15.321s

5 천만 행의 기준선은 00 : 01 : 15.321입니다. 5 억 행에 대해 직진하면 아마 ~ 12.5 분이됩니다.

절단

나는 이것에 대해 의심 스럽다. 그러나 그것은 가치가있다.

$ time cut -f50000000 -d$'\n' myfile.ascii
pgm_icnt = 0

real    5m12.156s

이것은 실행하는 데 00 : 05 : 12.156이 걸렸으며 이는 기준선보다 훨씬 느립니다! 중지하기 전에 전체 파일을 읽거나 5 천만 줄까지 읽었는지 확실하지 않지만 이것이 문제에 대한 실용적인 해결책처럼 보이지는 않습니다.

AWK

exit전체 파일이 실행될 때까지 기다리지 않기 때문에 솔루션 만 실행했습니다 .

$ time awk 'NR == 50000000 {print; exit}' myfile.ascii
pgm_icnt = 0

real    1m16.583s

이 코드는 00 : 01 : 16.583에서 실행되었는데, 이는 ~ 1 초 느리지 만 여전히 기준선의 개선은 아닙니다. 종료 명령이 제외 된 경우이 속도로 전체 파일을 읽는 데 약 ~ 76 분이 걸렸을 것입니다!

기존 Perl 솔루션도 실행했습니다.

$ time perl -wnl -e '$.== 50000000 && print && exit;' myfile.ascii
pgm_icnt = 0

real    1m13.146s

이 코드는 00 : 01 : 13.146에서 실행되었으며 기준보다 2 초 빠릅니다. 전체 500,000,000에서 실행하면 ~ 12 분이 걸릴 것입니다.

sed

보드의 최고 답변은 다음과 같습니다.

$ time sed "50000000q;d" myfile.ascii
pgm_icnt = 0

real    1m12.705s

이 코드는 00 : 01 : 12.705에서 실행되었는데, 이는 기준선보다 3 초 빠르며 Perl보다 ~ 0.4 초 빠릅니다. 전체 500,000,000 행에서 실행하면 ~ 12 분이 걸렸을 것입니다.

맵 파일

bash 3.1이있어 맵 파일 솔루션을 테스트 할 수 없습니다.

결론

대부분 head tail솔루션 을 개선하기가 어려운 것처럼 보입니다 . 기껏해야sed 솔루션은 ~ 3 %의 효율성 향상을 제공합니다.

(공식으로 계산 한 백분율 % = (runtime/baseline - 1) * 100)

50,000,000 행

  1. 00 : 01 : 12.705 (-00 : 00 : 02.616 = -3.47 %) sed
  2. 00 : 01 : 13.146 (-00 : 00 : 02.175 = -2.89 %) perl
  3. 00 : 01 : 15.321 (+00 : 00 : 00.000 = + 0.00 %) head|tail
  4. 00 : 01 : 16.583 (+00 : 00 : 01.262 = + 1.68 %) awk
  5. 00 : 05 : 12.156 (+00 : 03 : 56.835 = + 314.43 %) cut

행 500,000,000

  1. 00 : 12 : 07.050 (-00 : 00 : 26.160) sed
  2. 00 : 12 : 11.460 (-00 : 00 : 21.750) perl
  3. 00 : 12 : 33.210 (+00 : 00 : 00.000) head|tail
  4. 00 : 12 : 45.830 (+00 : 00 : 12.620) awk
  5. 00 : 52 : 01.560 (+00 : 40 : 31.650) cut

3,338,559,320 열

  1. 01 : 20 : 54.599 (-00 : 03 : 05.327) sed
  2. 01 : 21 : 24.045 (-00 : 02 : 25.227) perl
  3. 01 : 23 : 49.273 (+00 : 00 : 00.000) head|tail
  4. 01 : 25 : 13.548 (+00 : 02 : 35.735) awk
  5. 05 : 47 : 23.026 (+04 : 24 : 26.246) cut

4
전체 파일을 / dev / null에 넣는 데 시간이 얼마나 걸리는지 궁금합니다. (이것이 하드 디스크 벤치 마크 일 경우 어떻게됩니까?)
sanmai

3 개 이상의 공연 텍스트 파일 사전에 대한 소유권을 절실히 요구하고 있습니다. 이론적 근거가 무엇이든, 이것은 텍스트를 포용합니다. :)
Stabledog

51

함께 awk꽤 빠른입니다 :

awk 'NR == num_line' file

이것이 참이면 기본 동작은 awk다음과 같습니다 {print $0}..


대체 버전

파일이 크면 exit필요한 줄을 읽은 후 더 좋습니다 . 이렇게하면 CPU 시간을 절약 할 수 있습니다. 답변이 끝나면 시간 비교를보십시오 .

awk 'NR == num_line {print; exit}' file

bash 변수에서 줄 번호를 지정하려면 다음을 사용할 수 있습니다.

awk 'NR == n' n=$num file
awk -v n=$num 'NR == n' file   # equivalent

exit특히 줄이 파일의 첫 부분에있는 경우을 사용하여 시간이 얼마나 절약 되는지 확인하십시오.

# Let's create a 10M lines file
for ((i=0; i<100000; i++)); do echo "bla bla"; done > 100Klines
for ((i=0; i<100; i++)); do cat 100Klines; done > 10Mlines

$ time awk 'NR == 1234567 {print}' 10Mlines
bla bla

real    0m1.303s
user    0m1.246s
sys 0m0.042s
$ time awk 'NR == 1234567 {print; exit}' 10Mlines
bla bla

real    0m0.198s
user    0m0.178s
sys 0m0.013s

따라서 차이는 0.198 초 대 1.303 초로 약 6 배 더 빠릅니다.


awk가 필드 분할을 시도하기 때문에이 방법은 항상 속도가 느려집니다. 필드 분할의 오버 헤드는 다음으로 줄일 수 있습니다.awk 'BEGIN{FS=RS}(NR == num_line) {print; exit}' file
kvantour

이 방법에서 awk의 실제 성능은 file1의 n1 행, file2의 n2, n3 또는 file3 ...을 연결하려는 경우에 발생합니다 awk 'FNR==n' n=10 file1 n=30 file2 n=60 file3. GNU awk에서는 이것을 사용하여 속도를 높일 수 있습니다 awk 'FNR==n{print;nextfile}' n=10 file1 n=30 file2 n=60 file3.
kvantour

실제로 @kvantour, GNU awk의 다음 파일은 그러한 것들에 좋습니다. FS=RS필드 분할을 피하는 방법은 무엇입니까?
fedorqui 'SO 중지 피해'

1
FS=RS필드 분할을 피하지는 않지만 $ 0을 구문 분석하고 하나의 필드 만 할당합니다 RS.$0
kvantour

@kvantour 나는 몇 가지 테스트를 해왔으며 FS=RS타이밍에 차이가 없었습니다. 확장 할 수 있도록 그것에 대해 질문하는 것은 어떻습니까? 감사!
fedorqui 'SO 중지 피해'

29

내 테스트에 따르면 성능 및 가독성 측면에서 권장 사항은 다음과 같습니다.

tail -n+N | head -1

N원하는 줄 번호입니다. 예를 들어 tail -n+7 input.txt | head -1파일의 7 번째 줄을 인쇄합니다.

tail -n+Nline N에서 시작하는 모든 것을 인쇄 하고 head -1한 줄 후에 중지합니다.


대안 head -N | tail -1은 약간 더 읽기 쉽습니다. 예를 들어, 이것은 일곱 번째 줄을 인쇄합니다 :

head -7 input.txt | tail -1

성능면에서 작은 크기의 경우 큰 차이는 없지만 tail | head파일이 커지면 (위에서) 성능이 뛰어 납니다.

최고 투표권 sed 'NUMq;d'은 알고있는 것이 흥미롭지 만 헤드 / 테일 솔루션보다 더 적은 수의 사람들이 이해할 수 있으며 테일 / 헤드보다 느리다고 주장합니다.

테스트에서 테일 / 헤드 버전이 모두 성능이 우수했습니다. sed 'NUMq;d' 일관되게 되었습니다. 그것은 게시 된 다른 벤치 마크와 일치합니다. 꼬리 / 머리가 실제로 나쁜 경우를 찾기는 어렵습니다. 현대 유닉스 시스템에서 크게 최적화 될 것으로 예상되는 작업이기 때문에 놀라운 일이 아닙니다.

성능 차이에 대한 아이디어를 얻으려면 거대한 파일 (9.3G)에 대해 얻는 숫자입니다.

  • tail -n+N | head -1: 3.7 초
  • head -N | tail -1: 4.6 초
  • sed Nq;d: 18.8 초

결과는 다를 수 있지만, 성능이 수 head | tailtail | head, 일반적으로 작은 입력에 대한 비교, 그리고 sed중요한 요소 (5 배 주위 정도)에 의해 항상 느립니다.

내 벤치 마크를 재현하기 위해 다음을 시도 할 수 있지만 현재 작업 디렉토리에 9.3G 파일이 생성된다는 경고가 표시됩니다.

#!/bin/bash
readonly file=tmp-input.txt
readonly size=1000000000
readonly pos=500000000
readonly retries=3

seq 1 $size > $file
echo "*** head -N | tail -1 ***"
for i in $(seq 1 $retries) ; do
    time head "-$pos" $file | tail -1
done
echo "-------------------------"
echo
echo "*** tail -n+N | head -1 ***"
echo

seq 1 $size > $file
ls -alhg $file
for i in $(seq 1 $retries) ; do
    time tail -n+$pos $file | head -1
done
echo "-------------------------"
echo
echo "*** sed Nq;d ***"
echo

seq 1 $size > $file
ls -alhg $file
for i in $(seq 1 $retries) ; do
    time sed $pos'q;d' $file
done
/bin/rm $file

다음은 내 컴퓨터에서 실행 한 결과입니다 (SSD 및 16G 메모리가있는 ThinkPad X1 Carbon). 나는 마지막 실행에서 모든 것이 디스크가 아닌 캐시에서 온다고 가정합니다.

*** head -N | tail -1 ***
500000000

real    0m9,800s
user    0m7,328s
sys     0m4,081s
500000000

real    0m4,231s
user    0m5,415s
sys     0m2,789s
500000000

real    0m4,636s
user    0m5,935s
sys     0m2,684s
-------------------------

*** tail -n+N | head -1 ***

-rw-r--r-- 1 phil 9,3G Jan 19 19:49 tmp-input.txt
500000000

real    0m6,452s
user    0m3,367s
sys     0m1,498s
500000000

real    0m3,890s
user    0m2,921s
sys     0m0,952s
500000000

real    0m3,763s
user    0m3,004s
sys     0m0,760s
-------------------------

*** sed Nq;d ***

-rw-r--r-- 1 phil 9,3G Jan 19 19:50 tmp-input.txt
500000000

real    0m23,675s
user    0m21,557s
sys     0m1,523s
500000000

real    0m20,328s
user    0m18,971s
sys     0m1,308s
500000000

real    0m19,835s
user    0m18,830s
sys     0m1,004s

1
성능 다른 사이가 head | tailtail | head? 아니면 어떤 줄이 인쇄되고 있는지 (파일 시작과 파일 끝)에 따라 다릅니 까?
wisbucky

1
@wisbucky 나는 어려운 수치는 없지만 먼저 tail을 사용하고 "head -1"을 사용하는 한 가지 단점은 전체 길이를 미리 알아야한다는 것입니다. 당신이 그것을 모른다면, 당신은 그것을 먼저 계산해야 할 것이고, 이것은 성능 측면에서 손실이 될 것입니다. 또 다른 단점은 사용하기가 덜 직관적이라는 것입니다. 예를 들어 1에서 10까지의 숫자를 가지고 있고 세 번째 줄을 얻으려면 "tail -8 | head -1"을 사용해야합니다. "head -3 | tail -1"보다 오류가 발생하기 쉽습니다.
Philipp Claßen

죄송합니다. 분명한 예를 포함시켜야합니다. head -5 | tail -1tail -n+5 | head -1. 실제로 테스트 비교를 수행하고 tail | head더 빠른 것으로 나타났습니다 . stackoverflow.com/a/48189289
wisbucky

1
@wisbucky 언급 해 주셔서 감사합니다! 나는 몇 가지 테스트를했는데 내가 본 것과 라인의 위치에 관계없이 항상 약간 더 빠르다는 것에 동의해야합니다. 그것을 감안할 때, 나는 대답을 바꾸었고 누군가가 그것을 재현하고 싶을 때 벤치 마크를 포함시켰다.
Philipp Claßen

27

와우, 모든 가능성!

이 시도:

sed -n "${lineNum}p" $file

또는 Awk 버전에 따라 다음 중 하나입니다.

awk  -vlineNum=$lineNum 'NR == lineNum {print $0}' $file
awk -v lineNum=4 '{if (NR == lineNum) {print $0}}' $file
awk '{if (NR == lineNum) {print $0}}' lineNum=$lineNum $file

( 당신은 시도해야 할 수도 있습니다nawk 또는 gawk명령 ).

특정 라인 만 인쇄하는 도구가 있습니까? 표준 도구 중 하나가 아닙니다. 그러나 sed가장 사용하기 가장 쉬운 방법 일 것입니다.



21

이 질문은 Bash로 태그가 지정됩니다 .Bash (≥4) 수행 방법은 다음 mapfile과 같습니다. -s(건너 뛰기) 및 -n(count) 옵션 과 함께 사용 하십시오 .

파일의 42 번째 줄을 가져와야하는 경우 file:

mapfile -s 41 -n 1 ary < file

이 시점에서, ary줄을 포함하는 필드 file(후행 줄 바꿈 포함)를 갖게됩니다. 여기에서 처음 41 줄을 건너 뛰었습니다 (-s 41 )를 한 줄 ( -n 1)을 읽은 후 멈춘 . 이것이 실제로 42 번째 줄입니다. 인쇄하려면

printf '%s' "${ary[0]}"

줄 범위가 필요한 경우, 범위 42–666 (포함)을 말하고 직접 수학하고 싶지 않다고 stdout에 인쇄하십시오.

mapfile -s $((42-1)) -n $((666-42+1)) ary < file
printf '%s' "${ary[@]}"

이 행들도 처리해야한다면, 후행 줄 바꿈을 저장하는 것이 실제로 편리하지 않습니다. 이 경우-t 옵션 (trim)을 .

mapfile -t -s $((42-1)) -n $((666-42+1)) ary < file
# do stuff
printf '%s\n' "${ary[@]}"

함수가 당신을 위해 그렇게 할 수 있습니다.

print_file_range() {
    # $1-$2 is the range of file $3 to be printed to stdout
    local ary
    mapfile -s $(($1-1)) -n $(($2-$1+1)) ary < "$3"
    printf '%s' "${ary[@]}"
}

외부 명령이 없으며 Bash 내장 만!


11

sed print를 사용하여 종료 할 수도 있습니다.

sed -n '10{p;q;}' file   # print line 10

6
-n당신은 man 페이지를 순간적으로 발견했을 반드시 같은 옵션은 모든 라인을 인쇄 할 수있는 기본 동작을 사용하지 않습니다.
tripleee

에서 GNU sed 모든 sed대답은 동일한 속도에 대한 있습니다. 따라서 ( GNU의 경우 sed ) sed큰 파일과 작은 n 번째 줄 값의 시간을 절약 할 수 있기 때문에 이것이 가장 좋은 대답 입니다.
agc


6

큰 파일을위한 가장 빠른 솔루션은 항상 두 가지 거리를 제공하는 것입니다.

  • 파일의 시작부터 시작 줄까지. 전화합시다S
  • 마지막 줄부터 파일 끝까지의 거리 그것E

알려져 있습니다. 그런 다음 이것을 사용할 수 있습니다.

mycount="$E"; (( E > S )) && mycount="+$S"
howmany="$(( endline - startline + 1 ))"
tail -n "$mycount"| head -n "$howmany"

howmany는 필요한 줄 수입니다.

https://unix.stackexchange.com/a/216614/79743 에서 더 자세한 내용


1
S및 의 단위 E(예 : 바이트, 문자 또는 줄)를 명확히하십시오 .
agc

6

위의 모든 답변은 질문에 직접 답변합니다. 그러나 여기에 덜 직접적인 해결책이지만 잠재적으로 더 중요한 아이디어가 있습니다.

줄 길이는 임의적이므로 n 번째 줄 앞의 파일의 모든 바이트가 필요합니다 읽을 수 있습니다. 파일 크기가 크거나이 작업을 여러 번 반복해야하는 경우이 프로세스에 시간이 오래 걸리면 처음에 다른 방식으로 데이터를 저장해야하는지 신중하게 고려해야합니다.

실제 해결책은 예를 들어 파일의 시작 부분에 색인이 있어야 행이 시작되는 위치를 나타냅니다. 데이터베이스 형식을 사용하거나 파일 시작 부분에 테이블을 추가하기 만하면됩니다. 또는 큰 텍스트 파일과 함께 별도의 색인 파일을 작성하십시오.

예를 들어 줄 바꿈을위한 문자 위치 목록을 만들 수 있습니다.

awk 'BEGIN{c=0;print(c)}{c+=length()+1;print(c+1)}' file.txt > file.idx

그런 다음로 읽으십시오. tail실제로 seek파일의 해당 지점으로 직접 이동합니다!

예를 들어 1000 행 :

tail -c +$(awk 'NR=1000' file.idx) file.txt | head -1
  • awk는 "문자 인식"이지만 꼬리는 인식하지 않기 때문에 2 바이트 / 멀티 바이트 문자에서는 작동하지 않을 수 있습니다.
  • 큰 파일에 대해서는 이것을 테스트하지 않았습니다.
  • 이 답변 도 참조하십시오 .
  • 또는 파일을 작은 파일로 분할하십시오!

5

CaffeineConnoisseur의 매우 유용한 벤치마킹 답변에 대한 후속 조치로서 ... 'mapfile'방법이 다른 방법에 비해 얼마나 빠른지 궁금합니다 (테스트되지 않은). bash 4가 편리합니다. 사람들이 그 칭찬을 노래하고 있기 때문에 내가 대답하는 동안 최고 답변에 대한 주석 중 하나에서 언급 된 "꼬리 | 머리"방법 (머리 | 꼬리가 아닌) 방법의 테스트에서 re. 사용 된 테스트 파일 크기와 거의 같은 것이 없습니다. 짧은 통지로 찾을 수있는 가장 좋은 것은 14M 혈통 파일 (공백으로 구분 된 긴 줄은 12000 줄 미만)이었습니다.

짧은 버전 : mapfile은 cut 메소드보다 빠르지 만 다른 것보다 느리게 나타납니다. 꼬리 | 헤드 OTOH는 가장 빠를 수있는 것처럼 보이지만이 크기의 파일에서는 sed에 비해 그 차이가 크지 않습니다.

$ time head -11000 [filename] | tail -1
[output redacted]

real    0m0.117s

$ time cut -f11000 -d$'\n' [filename]
[output redacted]

real    0m1.081s

$ time awk 'NR == 11000 {print; exit}' [filename]
[output redacted]

real    0m0.058s

$ time perl -wnl -e '$.== 11000 && print && exit;' [filename]
[output redacted]

real    0m0.085s

$ time sed "11000q;d" [filename]
[output redacted]

real    0m0.031s

$ time (mapfile -s 11000 -n 1 ary < [filename]; echo ${ary[0]})
[output redacted]

real    0m0.309s

$ time tail -n+11000 [filename] | head -n1
[output redacted]

real    0m0.028s

도움이 되었기를 바랍니다!


4

다른 사람들이 언급 한 것을 사용 하여이 기능을 내 bash 쉘에서 신속하고 멋지게 만들었습니다.

파일을 작성하십시오. ~/.functions

내용을 추가하십시오 :

getline() { line=$1 sed $line'q;d' $2 }

그런 다음 이것을 다음에 추가하십시오 ~/.bash_profile.

source ~/.functions

이제 새로운 bash 창을 열면 다음과 같이 함수를 호출 할 수 있습니다.

getline 441 myfile.txt


3

\ n (일반적으로 새 줄)으로 구분하여 여러 줄을 얻은 경우. 'cut'도 사용할 수 있습니다.

echo "$data" | cut -f2 -d$'\n'

파일에서 두 번째 줄을 가져옵니다. -f3세 번째 줄을 제공합니다.


1
여러 줄을 표시하는 데에도 사용할 수 있습니다 cat FILE | cut -f2,5 -d$'\n'. FILE의 줄 2와 5를 표시합니다. (그러나 주문을 유지하지는 않습니다.)
Andriy Makukha

2

변수와 함께 sed를 행 번호로 사용하여 n 번째 행을 인쇄하려면 다음을 수행하십시오.

a=4
sed -e $a'q:d' file

여기서 '-e'플래그는 실행할 명령에 스크립트를 추가하기위한 것입니다.


2
콜론은 구문 오류이며 세미콜론이어야합니다.
tripleee 2019

2

좋은 답변이 많습니다. 나는 개인적으로 awk와 함께 간다. 편의를 위해 bash를 사용하는 경우 아래에를 추가하십시오 ~/.bash_profile. 그리고 다음에 로그인 할 때 (또는이 업데이트 후 .bash_profile을 소스로 제공하는 경우) 파일을 파이프 할 수있는 새로운 "nth"기능을 사용할 수 있습니다.

이것을 실행하거나 ~ / .bash_profile (bash를 사용하는 경우)에 넣고 bash를 다시여십시오 (또는 실행하십시오 source ~/.bach_profile)

# print just the nth piped in line nth () { awk -vlnum=${1} 'NR==lnum {print; exit}'; }

그런 다음 사용하려면 간단히 통과시킵니다. 예 :

$ yes line | cat -n | nth 5 5 line


1

한 번 봐 복용 후 정상 응답벤치 마크를 , 나는 작은 도우미 함수를 구현했습니다 :

function nth {
    if (( ${#} < 1 || ${#} > 2 )); then
        echo -e "usage: $0 \e[4mline\e[0m [\e[4mfile\e[0m]"
        return 1
    fi
    if (( ${#} > 1 )); then
        sed "$1q;d" $2
    else
        sed "$1q;d"
    fi
}

기본적으로 두 가지 방식으로 사용할 수 있습니다.

nth 42 myfile.txt
do_stuff | nth 42

0

위의 답변 중 일부를 짧은 bash 스크립트에 넣었습니다.이 스크립트는 파일에 넣고 get.sh연결할 수 있습니다 /usr/local/bin/get(또는 원하는 다른 이름).

#!/bin/bash
if [ "${1}" == "" ]; then
    echo "error: blank line number";
    exit 1
fi
re='^[0-9]+$'
if ! [[ $1 =~ $re ]] ; then
    echo "error: line number arg not a number";
    exit 1
fi
if [ "${2}" == "" ]; then
    echo "error: blank file name";
    exit 1
fi
sed "${1}q;d" $2;
exit 0

실행 파일인지 확인하십시오.

$ chmod +x get

PATH와 함께 사용할 수 있도록 연결

$ ln -s get.sh /usr/local/bin/get

책임감있게 즐기십시오!

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