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' -- {} +
의 경우 sed
macos가 stderr을 지원하는지 확실하지 않지만 /dev/fd/2
Linux 기반 시스템(macos는 Linux btw가 아님)에서도 w /dev/fd/2
stderr가 파이프 또는 터미널 장치와 같은 특정 유형의 파일로 이동하지 않는 한 사용은 잘못된 것입니다. -printf
GNU 구현에만 해당 find
되며 macOS를 포함한 다른 구현에서는 찾을 수 없습니다.
또한 이를 기반으로 하는 FreeBSD와 같은 macos에서는 대신 내부 편집을 수행 sed
해야 합니다 . 줄 번호를 보고 해야 하지만 문자열에 삽입하는 등의 작업을 수행할 수 없습니다. POSIX 호환 구현에서는 파일 간에도 재설정되지 않습니다 (GNU의 경우 또는 비표준 옵션을 사용할 때 재설정됩니다 ).-i ''
-i
sed
=
sed
sed
-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를 기반으로 하는 grep
API가 있으므로 (GNU 또는 최소한 FreeBSD를 기반으로 grep
했기 때문에 ) 거기에서 ( 짧은 변형 은 아니지만 ) 몇 가지 GNU 옵션을 찾을 수 있습니다. GNU에 대한 옵션도 있지만 안타깝게도 해당 옵션은 아직 사용할 수 없으므로 파일을 찾을 수 없으면 오류가 발생합니다.grep
--null
-Z
xargs
-0
-r
perl
find
해당 파일을 수정하지 않고 일치 항목과 대체 방법만 인쇄하려는 경우 다음과 같습니다.
find . -name '*.myfile' -type f -exec perl -nle '
$was = $_;
print "$ARGV($.): $was : $_" if s/abc/def/;
close ARGV if eof' -- {} +
-i
nplace가 없으면 -n
각 주기가 끝날 때 줄이 인쇄됩니다 n
. on이 자동으로 수행됩니다(그리고 출력을 추가하라는 메시지가 표시됩니다). 우리는 stderr 대신 stdout으로 인쇄합니다(stderr로 이동하려면 전체 명령을 stderr로 리디렉션합니다. 터미널의 대화형 셸 프롬프트에서 stdout과 stderr은 모두 터미널로 이동해야 하므로 변화).p
-l
chomp
$_
print
\n
>&2