다음 범위를 고려하십시오. 1,/pattern/
첫 번째 줄에서 패턴이 일치하면 범위는 전체 파일과 일치합니다.
$ cat 1.sh
#!/usr/bin/env bash
set -eu
seq 1 4 | sed -rn '1,/'"$1"'/p'
$ ./1.sh 1
1
2
3
4
$ ./1.sh 2
1
2
당신은 무엇을 하시겠습니까?
UPD제가 한 일은 다음과 같습니다(만약에 대비하여):
re='/1/'
seq 1 4 | sed -rn "1{$re{p;q}}; 1,${re}p"
아니면 이거:
seq 1 4 | sed -rn "1{/1/{p;q}}; 1,//p"
답변1
응, 짜증나는 일이야 sed
(봐봐sed
자주하는 질문대략 이 점). GNU sed
( GNU 특정) 를 사용하고 있으므로 -r
다음을 수행할 수 있습니다.
sed -En "0,/$1/p"
(저는 FreeBSD와 같은 다른 도구에서도 지원되고 일관성이 있기 때문에 -E
선호합니다 .-r
sed
grep
POSIX/Single UNIX 사양 표준의 다음 호)).
더 나은 대안(및 이식 가능)은 다음과 같습니다.
sed "/$1/q"
sed
첫 번째 게임이 끝나면 종료(그리고 읽기 중지)하라고 지시합니다.
문제가 없으므로 awk
다음과 같이 작성할 수 있습니다.
PATTERN=$1 awk 'NR==1, $0 ~ ENVIRON["PATTERN"]'
( for 와 비슷하지만 sed
작성하는 것이 좋습니다):
PATTERN=$1 awk '1; $0 ~ ENVIRON["PATTERN"] {exit}'
답변2
이는 정상적인 동작입니다 sed
. POSIX에서sed문서:
sed의 주소
주소는 파일의 입력 줄을 누적 계산하는 10진수, 입력의 마지막 줄 주소를 지정하는 "$" 문자 또는 컨텍스트 주소(sed의 정규 표현식에 설명된 대로 BRE로 구성됨)일 수 있습니다. 그 뒤에 구분 기호(보통 슬래시)가 옵니다.
주소가 없는 편집 명령은 각 패턴 공간을 선택해야 합니다.
주소가 있는 편집 명령은 해당 주소와 일치하는 모든 패턴 공간을 선택해야 합니다.
두 개의 주소가 있는 편집 명령은 첫 번째 주소와 일치하는 첫 번째 패턴 공간부터 두 번째 주소와 일치하는 다음 패턴 공간까지 포함 범위를 선택해야 합니다.. (두 번째 주소의 번호가 첫 번째 선택한 행 번호보다 작거나 같으면 한 행만 선택할 수 있습니다.) 선택한 범위 다음의 첫 번째 행부터 시작하여 sed는 첫 번째 주소를 다시 찾습니다. 그런 다음 이 과정을 반복해야 합니다. 다음 형식의 주소 부분 중 하나 또는 둘 다를 생략하면 정의되지 않은 결과가 생성됩니다.
[주소[,주소]]
sed
첫 번째 주소부터 다음 일치하는 주소까지 포함 범위가 인쇄되는 것을 볼 수 있습니다 .
귀하의 경우에는 1,/1/p
주소 sed
와 일치하므로 첫 번째 줄이 인쇄됩니다 1
. 그런 다음 두 번째 줄부터 시작하여 sed는 패턴과 일치하는 두 번째 주소를 검색합니다 /1/
. 발견되면 인쇄를 중지하십시오. 두 번째 줄부터 시작하면 일치하는 패턴이 없으므로 나머지를 인쇄하세요 /1/
.sed
위와 같이 sed를 사용하는 경우 1./2/p
첫 번째 줄을 인쇄하고 두 번째 줄은 패턴과 일치하여 인쇄 /2/
하고 sed
나머지를 반복합니다. 하지만 1
나머지 주소는 일치할 수 없으므로 sed
아무것도 인쇄되지 않습니다.
한 가지 예:
$ echo 1 2 3 1 4 1 | tr ' ' $'\n' | sed -rn '1,/1/p'
1
2
3
1
을 사용하므로 GNU sed
다음 양식을 사용할 수 있습니다 0,addr2
.
0,addr2
Start out in "matched first address" state, until addr2 is
found. This is similar to 1,addr2, except that if addr2 matches
the very first line of input the 0,addr2 form will be at the end
of its range, whereas the 1,addr2 form will still be at the
beginning of its range. This works only when addr2 is a regular
expression.
따라서 귀하의 명령은 다음과 같습니다.
seq 1 4 | tr ' ' $'\n' | sed -rn '0,/'"$1"'/p'
그 다음에:
$ ./1.sh 1
1
답변3
당신이 할 수 있는 일이 몇 가지 있습니다. 예를 들어 귀하의 의견은 귀하가 다음을 의미한다는 것을 나타냅니다.
...파일의 시작 부분부터 특정 줄(첫 번째 줄)까지 모든 것을 삭제합니다.
다음을 수행할 수 있습니다.
sed -n "/$1"'/,$p'
형태를 반전시키면 됩니다. 위 명령은 특정 줄부터 파일 끝까지만 인쇄합니다.
특정 줄을 인쇄하고 싶지 않다면...
sed -n "/$1"'/,$p' | sed 1d
... 트릭을 수행해야합니다 ...
그렇지 않으면 문제를 직접 해결하고 주기를 직접 처리할 수 있습니다.
seq 20 | sed -ne"/$1"'/!d;:B' -e'n;p;bB'
seq 20 | sed -n "/$1"'/!d;h;n;G;P;D'
두 명령 모두 패턴이 나타날 d
때까지 들어오는 각 줄을 삭제합니다 .$1
그런 다음 첫 번째 명령은 n
패턴 공간을 외부 입력 라인으로 덮어쓰고 :b
레이블을 설정합니다. 그런 다음 p
라인을 인쇄하고 라벨 로 돌아가기 n
전에 패턴 공간을 외부 라인으로 다시 덮어씁니다 . 파일 끝까지 이런 식으로 반복됩니다. 이 명령은 아마도 두 번째 명령보다 빠르며 더 적은 작업을 수행합니다.b
:b
두 번째는 h
일치하는 항목으로 이전 공간을 덮어씁니다 $1
. 그런 다음 입력의 추가 행으로 패턴 공간을 덮어씁니다 n
. 다음으로, G
공간을 확보하고 방금 가져온 입력 줄에 추가합니다. 이렇게 하면 두 줄의 순서가 바뀌고 개행 문자로 구분됩니다. 그것은 다음과 같습니다:
1호선 > 공간 확보
2호선 > 1호선
예약공간 >> 2호선
= 라인 2\n 라인 1
이 시점에서 패턴 공간에 나타나는 첫 번째 ewline 문자 sed
P
만 인쇄되고 나머지로 루프를 다시 시작하기 전에 동일한 요소 - end\n
D
언제나$1
첫 번째 일치 라인입니다각 라인. 따라서 일치하는 첫 번째 줄 $1
은 다음과 같습니다.언제나패턴 공간에서는안 돼요인쇄.
따라서 다음을 $1
인쇄 하면:5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
답변4
quit 명령을 포함하는 범위 다음에 함수 목록을 사용할 때 sed
범위를 유지하고 또는 -E
옵션을 사용하지 않을 수 있습니다(FreeBSD 및 GNU로 테스트됨).-r
sed
q
sed
printf '%s\n' {1..10} | sed -n '1,/1/{p;q;}'
# your solution adapted to work with FreeBSD sed as well
re='/1/'
printf '%s\n' {1..4} | sed -En "1{$re{p;q;};}; 1,${re}p"
printf '%s\n' {1..4} | sed -En "1{/1/{p;q;};}; 1,//p"