행 번호로 지정된 인접하지 않은 행 수정

행 번호로 지정된 인접하지 않은 행 수정

줄 번호를 미리 알고 다른 파일에 저장합니다.

cat linenos
2
15
42
44
... etc

보시다시피 행이 인접하지 않으므로 range 를 사용할 수 없습니다 sed. 목표는 대상 파일 행을 수정하는 것입니다. 예를 들어 대상 파일 행 앞에 MARKER와 같은 마커를 추가합니다.

sed간단한 접근 방식은 각 행을 수정하기 위해 여러 번 호출하는 것입니다.

for l in $(cat linenos)
do 
  sed -i "${l}s/^/MARKER/" target_file
done

이것은 분명히 sed를 여러 번 호출할 것입니다.

경고하다:* 이 접근 방식은 비효율적일 뿐만 아니라, 그러한 마크업을 삽입하지 않는 수정이 있을 경우에도 문제가 발생할 수 있습니다. sed 명령(예: dar)으로 행을 삭제하거나 삽입하면 루프에서 다음 sed 실행을 위해 linenos의 초기 행 번호가 무효화됩니다.

개선/최적화를 어떻게 제안하시나요?

예제 linenos 파일

cat linenos
2
5

샘플 개체 파일

cat target_file
line one
line two
line three
line four
line five
line six

수정된 target_file의 예상 결과

cat target_file
line one
MARKERline two
line three
line four
MARKERline five
line six

내가 생각해낸 가능한 방법은 sed 장면을 동적으로 생성하는 것입니다.

SEDCMD=$(for l in $(cat linenos); do echo -n "${l}s/^/MARK/;" ; done)

sed -i -e "$SEDCMD" targetfile

@스틸드라이버다음과 같은방법은 아이디어와 동일하지만 더 우아하고 간결합니다.

답변1

sed 자체(또는 선택한 다른 텍스트 처리 유틸리티)를 사용하여 줄 번호를 sed 표현식으로 변환한 다음 스위치를 사용하여 이를 -fsed 에 전달할 수 있습니다.

전임자.

sed 's:$:s/^/MARKER/:' linenos | sed -f- -i target_file

이것은 적어도 sed만 호출합니다.두 배.

답변2

perl(GNU 소스 sed) 사용 -i:

perl -pi -e '
  BEGIN{$l{0+$_}=1 while <STDIN>}
  $_ = "MARKER$_" if $l{$.}' target_file < linenos

perl우리는 stdin에 줄 번호 목록을 제공합니다. 이것은 BEGIN덩어리로 읽혀집니다.

각 입력 라인에 대해 를 사용하여 라인을 숫자로 변환합니다 0+$_. 이렇게 하면 개행 문자가 사라지고 숫자가 정규화됩니다(1e0, 1, 01이 모두 1이 됨).

해시 테이블은 각 행 번호의 값을 키로 %l채워집니다 .1

target_file현재 행 번호( ) 가 0이 아닌 값인 행의 앞에 추가되는 메인 루프 -p에서 처리합니다 .MARKERS$.%l

답변3

$ awk 'NR==FNR{a[$1]="MARKER"; next} {print a[FNR] $0}' linenos target_file
line one
MARKERline two
line three
line four
MARKERline five
line six

또는 약간의 메모리를 절약하십시오.

$ awk 'NR==FNR{a[$1]; next} {print (FNR in a ? "MARKER" : "") $0}' linenos target_file
line one
MARKERline two
line three
line four
MARKERline five
line six

"내부" 편집(perl 및 GNU sed와 동일 -i)을 원하는 경우 GNU awk를 사용하고 awk '...'명령문 앞에 a를 추가하여 awk -i inplace '...'파일이 비워지지 않도록 하세요. IMHO awk(또는 다른 UNIX 도구)를 사용하여 이 작업을 수행하는 것이 더 간단할 것입니다.print;nextlinenos

awk 'script' linenos target_file > tmp && mv tmp target_file

답변4

또 다른 접근 방식은 제자리에서 수정하는 ed대신 사용됩니다 .sedtarget_file

(while IFS= read n; do echo "${n}s/^/MARKER/"; done < linenos; echo w) |  ed -s target_file

관련 정보