유닉스의 텍스트 파일에서 미리 정해진 범위의 줄을 어떻게 추출 할 수 있습니까?


531

여러 데이터베이스 가치가있는 ~ 23000 행 SQL 덤프가 있습니다. 이 파일의 특정 섹션 (예 : 단일 데이터베이스의 데이터)을 추출하여 새 파일에 배치해야합니다. 원하는 데이터의 시작 및 끝 줄 번호를 모두 알고 있습니다.

16224와 16482 사이의 파일에서 모든 줄을 추출하여 새 파일로 리디렉션하는 유닉스 명령 (또는 일련의 명령)을 아는 사람이 있습니까?


당신이 큰 파일을 언급 이후, 나는 댓글을 확인하시기 바랍니다 stackoverflow.com/questions/83329/...을
sancho.s ReinstateMonicaCellio

답변:


792
sed -n '16224,16482p;16483q' filename > newfile

로부터 나오지 매뉴얼 :

p- 패턴 공간을 인쇄합니다 (표준 출력으로). 이 명령은 일반적으로 -n 명령 줄 옵션과 함께 사용해야합니다.

n- 자동 인쇄가 비활성화되지 않은 경우 패턴 공간을 인쇄 한 다음 패턴 공간을 다음 입력 라인으로 교체하십시오. 더 이상 입력이 없으면 더 이상 명령을 처리하지 않고 sed가 종료됩니다.

q-sed 더 이상의 명령이나 입력을 처리하지 않고 종료 합니다. -n 옵션으로 자동 인쇄를 비활성화하지 않으면 현재 패턴 공간이 인쇄됩니다.

sed 스크립트의 주소는 다음 형식 중 하나 일 수 있습니다.

number번호를 지정하면 입력에서 해당 줄만 일치합니다.

주소 범위는 쉼표 (,)로 구분 된 두 주소를 지정하여 지정할 수 있습니다. 주소 범위는 첫 번째 주소가 일치하는 위치부터 시작하여 두 번째 주소가 일치 할 때까지 계속됩니다.


3
이것이 원본 파일을 수정하는지 궁금합니다. 나는 경우를 대비하여 백업했으며 예상대로 원본을 수정하지 않은 것으로 보입니다.
Andy Groff

@AndyGroff. 파일을 제자리에 수정하려면 "-i"매개 변수를 사용하십시오. 그렇지 않으면 파일이 수정되지 않습니다.
youri

175
나와 같이 매우 큰 파일에서이 작업을 수행해야하는 경우 다음 줄에 quit 명령을 추가하면 도움이됩니다. 그런 다음 sed -n '16224,16482p;16483q' filename입니다. 그렇지 않으면 sed는 끝까지 (또는 적어도 내 버전에서는) 스캔을 계속합니다.
wds 2013

7
@MilesRout 사람들은 "비공개 이유는 무엇입니까?" 종종 "아무 신경 쓰지 않고" "무관심하다"라는 뜻일 것입니다.
Mark

1
@wds-귀하의 의견은 정상에 오르는 답변이 필요합니다. 낮과 밤의 차이를 만들 수 있습니다.
sancho.s ReinstateMonicaCellio

203
sed -n '16224,16482 p' orig-data-file > new-file

여기서 16224,16482는 시작 줄 번호와 끝 줄 번호입니다. 이것은 1 인덱스입니다. -n입력을 출력으로 에코하는 것을 억제합니다. 숫자는 다음 명령이 작동하게하는 라인 범위를 나타냅니다. 명령 p은 관련 행을 인쇄합니다.


7
큰 파일의 경우 위의 명령은 원하는 범위를 찾은 후에 전체 파일을 계속 걸어갑니다. 범위가 출력되면 sed가 파일 처리를 중지하는 방법이 있습니까?
게리

39
글쎄, 여기의 대답에서 , 범위의 끝에서 멈추는 것은 다음과 같이 이루어질 수있는 것처럼 보입니다 sed -n '16224,16482p;16482q' orig-data-file > new-file.
게리

5
왜 불필요한 공간에 넣은 다음 인용해야합니까? (물론 불필요한 문제를 만들고 해결하는 것이 컴퓨터 과학의 절반의 본질이지만 그 이유 외에는 ...)
Kaz

92

머리 / 꼬리를 사용하여 매우 간단합니다.

head -16482 in.sql | tail -258 > out.sql

sed를 사용하여 :

sed -n '16482,16482p' in.sql > out.sql

awk 사용 :

awk 'NR>=10&&NR<=20' in.sql > out.sql

1
두 번째 및 세 번째 옵션은 정상이지만 첫 번째 옵션은 1 개이면 2 개의 명령을 사용하기 때문에 많은 대안보다 느립니다. 또한 올바른 인수를 얻으려면 계산이 필요합니다 tail.
Jonathan Leffler

3
질문과 같은 줄 번호를 유지하려면 sed 명령이 있어야 sed -n 16224,16482p' in.sql >out.sql하고 awk 명령은awk 'NR>=16224&&NR<=16482' in.sql > out.sql
sibaz

3
또한 첫 번째 예제의 경우 head -16482 in.sql | tail -$((16482-16224)) >out.sql계산을 bash로 남겨 두는 것을 알 가치가 있습니다.
sibaz

1
q 옵션이 추가 된 경우에도 sed 버전보다 큰 파일에서 head 및 tail WAYYYY가 더 빠른 첫 번째 파일입니다. 헤드 버전 인스턴트 및 sed 버전 1 분 후 Ctrl-C ... 감사합니다
Miyagi

2
tail -n +16224계산을 줄이기 위해 사용할 수도 있습니다
SOFe

35

'vi'를 사용하고 다음 명령을 사용할 수 있습니다.

:16224,16482w!/tmp/some-file

또는

cat file | head -n 16482 | tail -n 258

편집 :-설명을 추가하기 위해 head -n 16482 를 사용 하여 첫 16482 줄을 표시 한 다음 tail -n 258 을 사용 하여 첫 번째 출력에서 ​​마지막 258 줄을 가져옵니다.


2
그리고 vi 대신 ex를 사용할 수 있습니다.
Tadeusz A. Kadłubowski

1
cat명령이 필요하지 않습니다 . head파일을 직접 읽을 수 있습니다. 1이 충분한 2 (그림에 표시된 3) 명령을 사용하기 때문에 많은 대안보다 속도가 느립니다.
Jonathan Leffler

1
@JonathanLeffler 당신은 꽤 틀 렸습니다. 엄청나게 빠릅니다. 몇 초 만에 500k 줄이있는 2G 파일에서 약 1G 인 200k 줄을 추출합니다 ( cat). 다른 솔루션에는 최소한 몇 분이 필요합니다. 또한 GNU에서 가장 빠른 변형은 다음과 같습니다 tail -n +XXX filename | head XXX.
Antonis Christofides

28

다른 접근 방식이 있습니다 awk.

awk 'NR==16224, NR==16482' file

파일이 크면 exit마지막으로 원하는 행을 읽은 후 좋을 수 있습니다 . 이렇게하면 불필요하게 다음 줄을 읽지 않습니다.

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file

awk 'NR==16224, NR==16482; NR==16482 {exit}' file

2
를 사용하여 런타임 및 리소스를 저장하기위한 1+ print; exit. 감사 !
Bernie Reiter

두 번째 예의 약간 단순화 :awk 'NR==16224, NR==16482; NR==16482 {exit}' file
Robin A. Meade

@ RobinA.Meade 감사합니다! 나는 게시물에 대한 당신의 생각 편집
fedorqui가 'SO 정지 해치지'


9
 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

6
cat dump.txt | head -16224 | tail -258

트릭을해야합니다. 이 접근법의 단점은 꼬리에 대한 인수를 결정하고 '사이에'에 끝 줄을 포함 시킬지 여부를 설명하기 위해 산술을 수행해야한다는 것입니다.


4
cat명령이 필요하지 않습니다 . head파일을 직접 읽을 수 있습니다. 1이 충분한 2 (그림에 표시된 3) 명령을 사용하기 때문에 많은 대안보다 속도가 느립니다.
Jonathan Leffler

@JonathanLeffler이 답변은 읽고 기억하는 것이 가장 쉬운 방법입니다. 실제로 성능에 관심이 있다면 처음에는 쉘을 사용하지 않았을 것입니다. 특정 도구가 특정 작업에 전념하도록하는 것이 좋습니다. 또한 "산술"은을 사용하여 확인할 수 있습니다 | tail -$((16482 - 16224)).
Yeti

6

boxxar의 어깨에 서서 나는 이것을 좋아합니다.

sed -n '<first line>,$p;<last line>q' input

예 :

sed -n '16224,$p;16482q' input

$수단 "마지막 줄에"첫 번째 명령은 수 있도록 sed라인으로 시작하는 모든 라인을 인쇄 16224하고, 두 번째 명령 차종은 sed종료 라인을 인쇄 16428. (추가 1에 대한 qboxxar의 솔루션 - 범위하는 것은 필요하지 않는 것 같습니다.)

끝 줄 번호를 두 번 지정할 필요가 없기 때문에이 변형이 마음에 듭니다. 그리고 사용 $이 성능에 해로운 영향을 미치지 않는다는 것을 측정했습니다 .



3

빠르고 더러운 :

head -16428 < file.in | tail -259 > file.out

아마도 최선의 방법은 아니지만 작동해야합니다.

BTW : 259 = 16482-16224 + 1.


1이 충분한 2 개의 명령을 사용하기 때문에 많은 대안보다 느립니다.
Jonathan Leffler

3

필자는 splitter 라는 Haskell 프로그램을 작성했습니다. 이는 내 릴리스 블로그 게시물을 읽으십시오 .

다음과 같이 프로그램을 사용할 수 있습니다.

$ cat somefile | splitter 16224-16482

그리고 그것이 전부입니다. Haskell을 설치해야합니다. 다만:

$ cabal install splitter

그리고 당신은 끝났습니다. 이 프로그램이 도움이 되길 바랍니다.


않는 splitter표준 입력에서 읽기 전용? 어떤 의미에서는 중요하지 않습니다. cat명령은 수행되지 않거나 여부를 불필요. 어느 사용 splitter 16224-16482 < somefile(이 파일 이름 인수를 경우) splitter 16224-16482 somefile.
Jonathan Leffler

3

명령 행에서 확인할 수 있습니다 :

cat filename|sed 'n1,n2!d' > abc.txt

예를 들어 :

cat foo.pl|sed '100,200!d' > abc.txt

6
cat이들 중 하나 에서 명령이 필요하지 않습니다 . sed파일 자체를 완벽하게 읽을 수 있거나 파일에서 표준 입력을 리디렉션 할 수 있습니다.
Jonathan Leffler

3

루비 사용하기 :

ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf

2

나는 머리 / 꼬리 트릭을 게시하려고했지만 실제로는 아마도 이맥스를 발사했을 것입니다. ;-)

  1. esc- x고토 라인 ret16224
  2. 마크 ( ctrl- space)
  3. esc- x고토 라인 ret16482
  4. esc-w

새 출력 파일을 열고 ctl-y 저장

무슨 일이 일어나고 있는지 보자.


4
내 경험상 Emacs는 매우 큰 파일에서 성능이 좋지 않습니다.
Greg Mattes

스크립트 작업으로 실행할 수 있습니까? 아니면 대화 형 옵션입니까?
Jonathan Leffler

2

나는 사용할 것이다 :

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR에는 파일에서 읽은 행의 레코드 (행) 번호가 포함됩니다.


2

변수를 사용하여 스크립트에서 동일한 작업을 수행하고 변수 이름을 p와 구분하기 위해 $ variable을 따옴표로 묶어 달성했습니다.

sed -n "$first","$count"p imagelist.txt >"$imageblock"

목록을 별도의 폴더로 나누고 초기 질문을 발견하고 유용한 단계에 답했습니다. (분할 명령은 이전 OS에서 옵션이 아니므로 코드를 이식해야합니다).


1

디렉토리를 포함하도록 PATH를 업데이트하거나 PATH에 이미 포함 된 디렉토리에 배치 할 수있는 한 명령 줄에서 실행할 수있는 작은 bash 스크립트를 작성했습니다.

사용법 : $ pinch filename start-line end-line

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0

1
1이 충분한 2 개의 명령을 사용하기 때문에 많은 대안보다 느립니다. 실제로 wc명령으로 인해 파일을 두 번 읽습니다 . 특히 기가 바이트 파일에서 디스크 대역폭을 낭비합니다. 모든 종류의 방법으로, 이것은 잘 문서화되어 있지만 엔지니어링 오버 킬입니다.
Jonathan Leffler

1

이것은 당신을 위해 일할 수 있습니다 (GNU sed) :

sed -ne '16224,16482w newfile' -e '16482q' file

또는 bash를 활용하십시오.

sed -n $'16224,16482w newfile\n16482q' file

1

ed 사용하기 :

ed -s infile <<<'16224,16482p'

-s진단 출력을 억제합니다. 실제 명령은 here-string에 있습니다. 특히, 원하는 회선 주소 범위 16224,16482p에서 p(print) 명령을 실행합니다 .


0

수락 응답의 -n이 작동합니다. 기울어 질 경우를 대비 한 다른 방법이 있습니다.

cat $filename | sed "${linenum}p;d";

이것은 다음을 수행합니다.

  1. 파일의 내용을 파이프하십시오 (또는 원하는 텍스트를 입력하십시오).
  2. sed는 주어진 줄을 선택하고 인쇄합니다
  3. d는 줄을 삭제해야합니다. 그렇지 않으면 sed는 모든 줄이 결국 인쇄 될 것이라고 가정합니다. 즉, d가 없으면 $ {linenum} p 부분이 인쇄되도록 요청하기 때문에 선택한 행으로 인쇄 된 모든 행이 두 번 인쇄됩니다. 나는 -n이 기본적으로 d와 같은 일을하고 있다고 확신합니다.

3
메모 cat file | sed로 더 잘 작성sed file
fedorqui 'SO 그만 해'

또한 이것은 단지 라인을 인쇄하는 반면 질문은 그 범위에 관한 것입니다.
fedorqui 'SO 중지 중지'

0

우리는 텍스트 파일에서 텍스트 줄을 추출하는 것에 대해 이야기하고 있기 때문에 특정 패턴과 일치하는 모든 줄을 추출하려는 특별한 경우를 제공합니다.

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

[데이터] 줄과 나머지를 인쇄합니다. 텍스트를 line1에서 패턴까지 원하는 경우 sed -n '1, / Data / p'myfile을 입력하십시오. 또한 두 가지 패턴을 알고 있으면 (텍스트에서 더 독창적 임) 범위의 시작 및 끝 줄을 모두 일치로 지정할 수 있습니다.

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