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인수는 건너뛸 줄 수가 아니라 여기에 1을 더한 값이라는 점에 유의하세요 tail. 이는 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

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

관련 정보