이것은 숙제이지만 구체적인 숙제 질문은 하지 않겠습니다.
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
이 경우에는 약간 과잉이지만 필터가 커지면 도움이 될 수 있습니다.