sed 변경 사항 + 해당 perl 구문 보고

sed 변경 사항 + 해당 perl 구문 보고

Linux 및 Perl을 배우는 초보자:

(a) 대체 문자열을 검색하고, (b) 파일 이름 패턴을 일치시키고 싶습니다..myfile., (c) 하위 디렉토리에서 재귀적으로 검색하고, (d) 줄 번호, 파일 이름, 원래 줄 및 변경된 줄을 인쇄합니다.

sed나는 사용하는 버전 과 구문을 모두 찾고 있습니다 perl. 나는 여기서 출발점을 찾았다질문하지만:

첫째: sed

필수: 패턴 일치 구문 추가.myfile., 재귀적으로 검색하고, 줄 번호를 인쇄하고 제거합니다. w /dev/fd/2-- 무슨 일을 하는지 모르겠습니다. 파일을 출력하는 것이 아니라 결과를 터미널에 인쇄하고 싶습니다. 참고: 저는 Mac OS에서 Visual Studio Terminal을 사용하고 있습니다.

find . -type f -printf '\n%p:\n' -exec sed -i '/foo/{
h
s//bar/g
H
x
s/\n/ >>> /
w /dev/fd/2
x
}' {} \;

산출:

./file1:
foo stuff >>> bar stuff
more foo >>> more bar

./file2:

./file3:
foo first >>> bar first
third: foo >>> third: bar

두 번째: 펄:

필수: 패턴 일치 구문 추가.myfile., 재귀 검색. 또한 줄 번호 출력도 $.잘못되었습니다. 첫 번째 파일에 대해서는 정확하지만 계속해서 계산되며 더 많은 파일을 검색할 때 재설정되지 않습니다(참조:첨부된 스크린샷출력용).

$ find . -type f | 
   xargs perl -i -ne '$was=$_; chomp($was);
                      s/abc/def/ && print STDERR "$ARGV($.): $was : $_"' 
./foo(1): fooabcbar : foodefbar

답변1

이 코드는 수정 사항을 stderr에 인쇄하는 동안( 또는 를 통해) 파일을 내부에서 수정합니다(물론, -p; 대신 -n;를 사용하면 -n파일이 비워지는 Perl 코드의 경우) w /dev/fd/2.print STDERR

그러나 find . | xargs출력이 find예상 입력 형식과 호환되지 않기 때문에 이는 잘못된 것입니다 xargs. 또한 현재 입력 줄 번호가 perl포함된 in은 각 파일 끝의 핸들을 닫지 않는 한 파일 간에 재설정되지 않으므로 다음과 같아야 합니다.$.ARGV

find . -name '*.myfile' -exec perl -i -pe '
  chomp($was = $_);
  print STDERR "$ARGV($.): $was : $_" if s/abc/def/;
  close ARGV if eof' -- {} +

의 경우 sedmacos가 stderr을 지원하는지 확실하지 않지만 /dev/fd/2Linux 기반 시스템(macos는 Linux btw가 아님)에서도 w /dev/fd/2stderr가 파이프 또는 터미널 장치와 같은 특정 유형의 파일로 이동하지 않는 한 사용은 잘못된 것입니다. -printfGNU 구현에만 해당 find되며 macOS를 포함한 다른 구현에서는 찾을 수 없습니다.

또한 이를 기반으로 하는 FreeBSD와 같은 macos에서는 대신 내부 편집을 수행 sed해야 합니다 . 줄 번호를 보고 해야 하지만 문자열에 삽입하는 등의 작업을 수행할 수 없습니다. POSIX 호환 구현에서는 파일 간에도 재설정되지 않습니다 (GNU의 경우 또는 비표준 옵션을 사용할 때 재설정됩니다 ).-i ''-ised=sedsed-i-s

.myfile포함되지 않은 파일을 포함하여 모든 파일을 편집(및 교체)합니다 abc. 이 문제는 다음을 통해 해결할 수 있습니다.

find . -name '*.myfile' -type f -exec grep -l --null abc {} + |
  xargs -0 perl -i -pe '
  chomp($was = $_);
  print STDERR "$ARGV($.): $was : $_" if s/abc/def/;
  close ARGV if eof' --

Macos에는 일부 이전 버전의 GNU를 기반으로 하는 grepAPI가 있으므로 (GNU 또는 최소한 FreeBSD를 기반으로 grep했기 때문에 ) 거기에서 ( 짧은 변형 은 아니지만 ) 몇 가지 GNU 옵션을 찾을 수 있습니다. GNU에 대한 옵션도 있지만 안타깝게도 해당 옵션은 아직 사용할 수 없으므로 파일을 찾을 수 없으면 오류가 발생합니다.grep--null-Zxargs-0-rperlfind

해당 파일을 수정하지 않고 일치 항목과 대체 방법만 인쇄하려는 경우 다음과 같습니다.

find . -name '*.myfile' -type f -exec perl -nle '
  $was = $_;
  print "$ARGV($.): $was : $_" if s/abc/def/;
  close ARGV if eof' -- {} +

-inplace가 없으면 -n각 주기가 끝날 때 줄이 인쇄됩니다 n. on이 자동으로 수행됩니다(그리고 출력을 추가하라는 메시지가 표시됩니다). 우리는 stderr 대신 stdout으로 인쇄합니다(stderr로 이동하려면 전체 명령을 stderr로 리디렉션합니다. 터미널의 대화형 셸 프롬프트에서 stdout과 stderr은 모두 터미널로 이동해야 하므로 변화).p-lchomp$_print\n>&2

관련 정보