이 주제에 관해 비슷한 질문과 해결 방법을 찾았지만 문제를 해결할 수 없습니다.for 루프이전에 제안된 솔루션을 사용합니다.
파일 B:
88569.abcrat
44689.defhom
3702.ghigop
234라는 파일의 텍스트 예:
9606.jklpan
how is the weather
88569.abcrat
today is a sunny day
44689.defhom
tomorrow will be a rainy day
3702.ghigop
yesterday was a cloudy day
10116.zyxtak
i am happy to see rainbow
234라는 파일에 대한 원하는 출력:
9606.jklpan
how is the weather
10116.zyxtak
i am happy to see rainbow
그런 다음 fileA에 나열된 다른 파일에 대해 검색, 일치 및 삭제 프로세스를 반복해야 합니다.
파일 A:
234
123
456
나는 노력하고 있습니다 :
for i in $(cat fileA); do for j in $(cat fileB); do awk "/$j/ {while (/$j/ && getline>0) ; next} 1" $i; done; done
for i in $(cat fileA); do for j in $(cat fileB); do sed -e "/**$i/$j**/ { N; d; }" $i; done; done
그러나 지금까지 그들 중 누구도 작동하지 않습니다. 뭔가 문제가 있는 것 같습니다. 여기서 도움을 받기를 바랍니다. 가능하다면 더 나은 명령 제안이 있을 수도 있습니다.
그리고 두 번째 스크립트에서 굵은 글씨 부분을 제대로 썼는지 알고 싶습니다.
추신: 저는 스크립팅 초보자입니다. 제공된 도움에 감사드립니다. 감사해요!
답변1
내 이해에 따르면 이름이 파일에 저장되어 있는 파일이 여러 개 있고 fileA
저장된 텍스트를 제외하고 각 파일의 모든 내용을 인쇄하여 fileB
다음을 수행할 수 있습니다.
while read -r file_name
do
grep -v -f <(grep -A1 -f fileB "$file_name") "$file_name"
done < file
내용이 인쇄됩니다 stdout
.
답변2
fileA
의 파일 이름이 정확히 한 줄에 하나씩 나열되고 파일 이름에 개행( \n
) 문자가 포함되지 않은 경우 다음이 유효합니다.
$ xargs -d'\n' <fileA \
perl -MFile::Slurp -e '
my @patterns=read_file(shift, {chomp=>1});
$re = join ("|",@patterns);
while (<>) {
if (m/$re/o) { readline; next };
print
}' fileB
9606.jklpan
how is the weather
10116.zyxtak
i am happy to see rainbow
xargs
Perl 스크립트에 파일 이름 매개변수 목록을 제공하는 데 사용되며 fileA
한 번에 한 줄씩 읽습니다.
Perl 스크립트는 먼저 fileB
명령줄( )에서 첫 번째 파일 이름 인수를 읽고 각 줄을 결합하는 정규식을 작성합니다( chomp
각 입력 줄을 끝내는 개행 문자 뒤).
그 후, 나머지 각 파일 이름 인수를 반복하여 일치하는 줄과 다음 줄을 건너뛰고 나머지 줄을 인쇄합니다.
이 스크립트는 단순히 모든 입력 파일의 출력을 stdout으로 인쇄하고 다른 입력 파일의 출력을 구별하려고 시도하지 않습니다.
각 입력 파일의 출력을 다른 출력 파일로 이동하려면(예: 파일 출력이 234
로 이동 ) 전체 루프를 다음과 같이 바꿀 234.new
수 있습니다 .while (<>) {...}
my $lastfn="";
while (<>) {
if(eof) { close(OUTFILE) };
if ($lastfn != $ARGV) {
$lastfn=$ARGV;
open(OUTFILE,">","$ARGV.new")
};
if (m/$re/o) { readline; next; };
print OUTFILE
}
또는 출력에 파일 이름만 표시하려는 경우:
my $lastfn="";
my $nl=""; # we dont want to print a LF before the first output filename
while (<>) {
if ($lastfn != $ARGV) {
print "$nl", $ARGV,":\n";
$nl="\n";
$lastfn=$ARGV };
};
if (m/$re/o) { readline; next };
print
}
또는 각 출력 줄에 입력 파일 이름을 붙입니다.
while (<>) {
if (m/$re/o) { readline; next };
print "$ARGV:$_"
}
마지막으로 xargs 없이도 perl로 완전히 수행할 수 있습니다.
$ perl -MFile::Slurp -e '
my @patterns=read_file(shift, {chomp=>1});
$re = join ("|",@patterns);
my @files=read_file(shift, {chomp=>1});
@ARGV=@files;
while (<>) {
if (m/$re/o) { readline; next };
print
}' fileB fileA
답변3
먼저 fileB를 확인하여 sed 명령 파일을 빌드한 다음 해당 명령 파일을 fileA에 나열된 파일에 적용하여 이 문제를 해결하겠습니다.
여기서 주목해야 할 점은 나중에 사용할 때 유효한 sed 구문이어야 하기 때문에 fileB의 내용을 인용하고 있다는 것입니다.
$ sed -e '
s:[][\/.^$*]:\\&:g
s:.*:/&/{$q;N;d;}:
' < fileB > cmds
$ < fileA xargs -d'\n' -r -l sed -f cmds
문제 해결에 대한 또 다른 관점은 fileB의 행을 해시된 키로 저장한 다음 fileA에 나열된 파일을 읽을 때 키가 있는지 확인하는 것입니다.
$ < fileA xargs -d'\n' -r \
perl -ne 'BEGIN { $argc = @ARGV - 1; }
@ARGV == $argc and $h{$_}++,next;
print,close(ARGV) if eof;
my $n = <>;
print $_,$n if ! exists $h{$_};
' fileB