줄 번호를 미리 알고 다른 파일에 저장합니다.
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 표현식으로 변환한 다음 스위치를 사용하여 이를 -f
sed 에 전달할 수 있습니다.
전임자.
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;
next
linenos
awk 'script' linenos target_file > tmp && mv tmp target_file
답변4
또 다른 접근 방식은 제자리에서 수정하는 ed
대신 사용됩니다 .sed
target_file
(while IFS= read n; do echo "${n}s/^/MARKER/"; done < linenos; echo w) | ed -s target_file