그래서 이것은 숙제를위한 것이지만 구체적인 숙제에 대해서는 묻지 않을 것입니다.
하나의 파일에서 다른 라인 세트를 가져 오기 위해 head와 tail을 사용해야합니다. 따라서 6-11 행과 19-24 행과 같이 두 파일을 다른 파일에 저장하십시오. 나는 다음과 같은 추가를 사용하여 이것을 할 수 있다는 것을 안다.
head -11 file|tail -6 > file1; head -24 file| tail -6 >> file1.
그러나 나는 우리가해야한다고 생각하지 않습니다.
head 및 tail 명령을 결합한 다음 파일에 저장할 수있는 특정 방법이 있습니까?
답변
다음과 같은 구문 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
답변
{ … }
그룹화 구문을 사용하여 경로 재 지정 연산자를 복합 명령에 적용 할 수 있습니다 .
{ head -n 11 file | tail -n 6; head -n 24 file | tail -n 6; } >file1
첫 번째 M + N 행을 복제하고 마지막 N 만 유지하는 대신 첫 번째 M 행을 건너 뛰고 다음 N을 복제 할 수 있습니다. 이는 큰 파일에서 훨씬 빠릅니다 . 것을주의 +N
의 인수가 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 또는 awk 와 같은보다 일반적인 도구를 호출하는 것 입니다. (이 속도는 느려질 수 있지만 매우 큰 파일에만 중요합니다.)
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
답변
나는 당신이 머리와 꼬리를 사용해야한다고 말했지만 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가 더 효율적입니다.
답변
로에게 sed
당신이 할 수 있습니다 :
sed '24q;1,5d;12,18d' <infile >outfile
… 아마도 더 효율적인 솔루션이있을 수 있습니다 head
. Don은 이미 그 방법이 잘 작동하는 방법을 이미 보여 주었지만, 나는 그것도 가지고 놀았습니다. 이 특정한 경우를 처리하기 위해 할 수있는 일 :
for n in 5 6 7 6
do head -n"$n" >&"$((1+n%2))"
done <infile >outfile 2>/dev/null
… 반복의 값 이 짝수인지 홀수 인지 에 따라 head
4 번이나 호출 합니다 .outfile
/dev/null
$n
더 일반적인 경우에는 이미 가지고있는 다른 것들과 함께 이것을 조롱했습니다.
somehead()(
### call it like:
### somehead -[repeat] [-][numlines]* <infile >outfile
set -e -- "${1#-}" "$@" #-e for arg validation
r=; cd -- "${TMP:-/tmp}" #go to tmp
dd bs=4096 of="$$$$" <&4 2>&3 & #dd <in >tmpfile &bg
until [ -s "$$$$" ]; do :; done #wait while tmpfile empty
exec <"$$$$" 4<&-; rm "$$$$" #<tmpfile; rm tmpfile
[ "$3${1}0" -ne "$3${2#?}0" ] || #validate args - chk $1
shift "$(((r=-${1:--1})||1))"; shift #shift 1||2
while [ "$(((r+=(_n=1))-1))" -ne 0 ] && #while ! $rptmax &&
IFS= read -r l && # ! EOF &&
printf "%.$(($1>0?${#l}+1:0))s" "$l # ? printf do
"; do for n do [ "${n#-}" -gt 0 ] || exit #args all -[nums>0]
head "-n$((${n#-}-_n))" >&"$((n>(_n=0)?1:3))" #head -n?$1 >?[+-]
done; done #done and done
) 4<&0 3>/dev/null #4<for dd 3>for head
이것은 다음과 같은 일을 할 수 있습니다.
seq 100 | somehead -1 -5 6 -7 6
… 인쇄 …
6
7
8
9
10
11
19
20
21
22
23
24
첫 번째 인수는 접두사로 시작하는 반복 횟수 -
, 또는 실패한 경우에만 a -
입니다. 카운트가 제공되면 지정된 횟수만큼 다음 args에 주어진 라인 패턴을 반복하고 그렇게되면 중지합니다.
다음에 나오는 각 인수에 대해 기록해야하는 행 수를 나타 내기 위해 음의 정수를 해석하고에 기록되어야 /dev/null
하는 행 수를 나타 내기 위해 양의 정수를 해석합니다 stdout
.
따라서 위의 예에서는 처음 5 행을 /dev/null
다음에 6 stdout
, 다음 7을 /dev/null
다시, 다음 6을 다시 한 번에 인쇄합니다 stdout
. 마지막 인수에 도달하고 -1
반복 횟수를 완전히 순환 하면 종료됩니다. 첫 번째 인수가 -2
있었다면 프로세스를 한 번 더 반복했거나 -
가능한 한 오랫동안 진행했을 것입니다.
각 인수주기마다 while
루프가 한 번 처리됩니다. 각 루프의 맨 위에서 첫 번째 줄부터 stdin
쉘 변수를 읽습니다 $l
. 이것은 while head </dev/null; do :; done
무한정 반복 되기 때문에 필요 head
합니다. 파일 끝에 도달하면 리턴으로 표시합니다. EOF에 대한 확인을하기 위해 최선을 다하고 있습니다 있도록 read
하고 printf
기록합니다 $l
에 플러스 바꿈을 stdout
두 번째 인수는 양의 정수 경우에만.
이 read
검사는 다른 루프가 호출 된 직후에 루프를 약간 복잡하게 만듭니다. 루프 는 상위 루프 의 각 반복 에 대해 표시된대로 for
args 2-$#
를 $n
반복 while
합니다. 즉, 각 반복에 대해 첫 번째 arg는 명령 행에 지정된 값에서 하나씩 감소해야하지만 다른 모든 값은 원래 값을 유지해야하므로 $_n
마커 var의 값을 각 값에서 빼야합니다. 첫 번째 인수의 값이 0보다 큽니다.
이는 함수의 주요 루프를 구성하지만 대부분의 코드는 맨 위에 있으며 함수를 파이프로 입력으로 깔끔하게 버퍼링 할 수 있도록 고안되었습니다. 이것은 먼저 backgrounded dd
를 호출하여 블록 크기가 4k 인 출력에서 tmpfile에 복사합니다. 그런 다음 함수는 홀드 루프를 설정합니다. 단일 루프에서도 거의 완료되지 않아야 dd
합니다. 함수보다 먼저 파일에 단일 쓰기를 한 다음 stdin을 tmpfile에 연결된 파일 설명 자로 바꿉니다. 그 후 즉시 파일을 연결 해제합니다rm
. 이것은 함수가 트랩을 요구하지 않고 또는 정리를 위해 스트림을 안정적으로 처리 할 수있게합니다. 함수가 fd에서 클레임을 해제하자마자 명명 된 파일 시스템 링크 만 이미 제거되었으므로 tmpfile의 존재가 중지됩니다.
답변
다음과 같이 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
이 경우 약간 과잉이지만 필터가 커지면 이익이 될 수 있습니다.