head와 tail을 사용하여 다양한 라인 세트를 가져와 동일한 파일에 저장

head와 tail을 사용하여 다양한 라인 세트를 가져와 동일한 파일에 저장

이것은 숙제이지만 구체적인 숙제 질문은 하지 않겠습니다.

head와 tail을 사용하여 파일에서 다른 행 세트를 가져와야 합니다. 6-11행과 19-24행과 유사하며 둘 다 다른 파일에 저장합니다. 나는 추가를 사용하여 이 작업을 수행할 수 있다는 것을 알고 있습니다.

head -11 file|tail -6 > file1; head -24 file| tail -6 >> file1. 

하지만 나는 우리가 그렇게 해서는 안 된다고 생각합니다.
head 및 tail 명령을 결합한 다음 파일에 저장하는 특별한 방법이 있습니까?

답변1

유사한 구조를 사용하여 명령을 그룹화하는 경우 head별도의 기본 연산을 사용하여 이를 수행 할 수 있습니다.{ ... ; }

{ head -n ...; head -n ...; ...; } < input_file > output_file

모든 명령은 동일한 입력을 공유합니다(감사합니다@mikeserv).
6-11 및 19-24 행을 얻는 것은 다음과 같습니다.

head -n 5 >/dev/null  # dump the first 5 lines to `/dev/null` then
head -n 6             # print the next 6 lines (i.e. from 6 to 11) then
head -n 7 >/dev/null  # dump the next 7 lines to `/dev/null` ( from 12 to 18)
head -n 6             # then print the next 6 lines (19 up to 24)

따라서 기본적으로 다음을 실행합니다.

{ head -n 5 >/dev/null; head -n 6; head -n 7 >/dev/null; head -n 6; } < input_file > output_file

답변2

{ … }그룹화된 구문을 사용하여 복합 명령에 리디렉션 연산자를 적용할 수 있습니다 .

{ head -n 11 file | tail -n 6; head -n 24 file | tail -n 6; } >file1

처음 M+N개 행을 복사하고 마지막 N개 행만 유지하는 대신 처음 M개 행을 건너뛰고 다음 N개 행을 복사할 수 있습니다. 이것은대용량 파일이 훨씬 빠르게 처리됩니다.. 매개 +N변수 tail는 건너뛸 줄 수가 아니라 1을 더한 것입니다. 즉, 인쇄할 첫 번째 줄의 줄 번호이며 줄 번호는 1부터 시작합니다.

{ tail -n +6 file | head -n 6; tail -n +19 file | head -n 6; } >file1

어느 쪽이든 출력 파일은 한 번만 열리지만 입력 파일은 각 조각을 추출하기 위해 한 번 순회됩니다. 입력을 그룹화하는 방법은 무엇입니까?

{ tail -n +6 | head -n 6; tail -n +14 | head -n 6; } <file >file1

일반적으로 말하면 이것은 작동하지 않습니다. (적어도 입력이 일반 파일인 경우 일부 시스템에서는 작동할 수 있습니다.) 왜 그럴까요? 왜냐하면입력 버퍼. 대부분의 프로그램(포함 tail)은 입력을 바이트 단위로 읽지 않고 한 번에 몇 킬로바이트씩 읽습니다. 그게 더 빠르기 때문입니다. 따라서 tail몇 킬로바이트를 읽고, 처음에 조금 건너뛰고, 조금 더 전달한 head다음 중지합니다. 그러나 읽은 내용은 읽혀지며 다음 명령에는 사용할 수 없습니다.

또 다른 방법head파이프를 사용하는 것입니다/dev/null행을 건너뜁니다.

{ head -n 5 >/dev/null; head -n 6; head -n 7 >/dev/null; head -n 6; } <file >file1

다시 말하지만 버퍼링으로 인해 작동이 보장되지는 않습니다. head입력이 일반 파일에서 나올 때 GNU coreutils(비임베디드 Linux 시스템의 명령)의 명령과 함께 작동합니다. 왜냐하면 이 구현이 head원하는 것을 읽고 나면파일 위치 설정출력이 없는 첫 번째 바이트로. 입력이 파이프인 경우에는 아무런 효과가 없습니다.

파일에서 여러 줄의 시퀀스를 인쇄하는 더 쉬운 방법은 보다 일반적인 도구를 호출하는 것입니다.sed또는. (느릴 수 있지만 매우 큰 파일에만 작동합니다.)

sed -n -e '6,11p' -e '19,24p' <file >file1
sed -e '1,5d' -e '12,18d' -e '24q' <file >file1
awk '6<=NR && NR<=11 || 19<=NR && NR<=24' <file >file1
awk 'NR==6, NR==11; NR==19, NR==24' <file >file1

답변3

head와 tail을 사용해야 한다고 말씀하셨지만 여기서 작업에는 확실히 sed가 더 쉬운 도구입니다.

$ cat foo
a 1 1
a 2 1
b 1 1
a 3 1
c 3 1
c 3 1
$ sed -ne '2,4p;6p' foo
a 2 1
b 1 1
a 3 1
c 3 1

다른 프로세스를 사용하여 문자열에 블록을 만들고 sed를 통해 실행할 수도 있습니다.

$ a="2,4p;6p"
$ sed -ne $a foo
a 2 1
b 1 1
a 3 1
c 3 1

-n 출력을 부정한 다음 p를 사용하여 인쇄할 범위를 지정합니다. 범위의 첫 번째 숫자와 마지막 숫자는 쉼표로 구분됩니다.

즉, @don_crissti가 제안한 명령 그룹화를 수행하거나 파일을 몇 번 반복하면서 매번 머리/꼬리 부분에 있는 줄 덩어리를 잡을 수 있습니다.

$ head -4 foo | tail -3; head -6 foo | tail -1
a 2 1
b 1 1
a 3 1
c 3 1

파일에 줄과 블록이 많을수록 sed가 더 효율적입니다.

답변4

다음과 같이 bash 기능을 사용하십시오.

seq 1 30 > input.txt
f(){ head $1 input.txt | tail $2 >> output.txt ;}; f -11 -2; f -24 -3
cat output.txt
10
11
22
23
24

이 경우에는 약간 과잉이지만 필터가 커지면 도움이 될 수 있습니다.

관련 정보