약 10만 개의 파일이 있고 각 파일에 대해 다음을 수행하고 싶습니다.
다음 ASCII 코드를 포함하는 파일의 다섯 번째 문자와 여섯 번째 문자 사이에 0x1f
문자열이 있습니다 . 이제 애플리케이션이 모든 교체 목록이 포함된 특정 파일을 열도록 하고 싶습니다. 나중에 이 교체 파일의 형식을 참조하세요. 대체 항목이 파일에 없는 경우 파일 이름을 stderr에 기록하면 나중에 파일을 수동으로 수정할 수 있습니다. 이제 ascii 코드의 16~17번째 문자 사이에 0x1f
대체할 내용이 다시 나타나게 되는데, 이번에는 해당 필드가 단순히 대체할 내용이 아니라 대체할 내용을 담은 html 문자열로 대체할 수 있습니다. 한 번 또는 여러 번. 필드의 첫 번째 항목만 바꾸고 싶습니다.
대체 파일의 형식은 매우 간단합니다. 각 대체 항목은 한 줄에 공백으로 구분되어 있습니다. 교체되는 길이에 따라 정렬됩니다.
예
대체 파일:
CCCC 3
BCC 233
CCA 331
CCB 332
ACC 133
AA 11
AB 12
BA 21
BB 22
CC 33
A 1
B 2
위와 같은 문자와 숫자가 반드시 포함되어야 한다는 보장은 없습니다. 이는 단지 예시일 뿐이며 UTF-8이 포함될 수 있습니다.
파일: (0x1f 문자는 다음 예에서 ^_로 기록됩니다.)
field1^_field2^_field3^_field4^_field5^_BB^_field7^_hai
this field contains a newline^_some UTF-8オイ^_the next field is empty^_^_
another newline^_field14^_field15^_<b>BB</b>stuff BB^_the previous field contains something to replace^_^_^_more fields...
파일은 다음과 같습니다.
field1^_field2^_field3^_field4^_field5^_22^_field7^_hai
this field contains a newline^_some UTF-8オイ^_the next field is empty^_^_
another newline^_field14^_field15^_<b>22</b>stuff BB^_the previous field contains something to replace^_^_^_more fields...
내 입력의 실제 예를 업로드했습니다.여기. 이 파일의 원하는 출력은 다음과 같습니다.여기( RYO
로 대체되어야 함 リョ
).
약간의 배경
일부 바보는 데이터베이스에 별도의 열을 생성하지 않고 대신 단일 열을 생성하고 필드를 0x1f 문자로 구분하기로 결정했습니다. 그는 또한 내가 변경하고 싶은 정보를 두 가지 다른 분야에 복사하는 것이 가능할 것이라고 생각했습니다. 데이터베이스의 정보를 pr 파일로 추출합니다. 행에는 필드가 있는 열만 포함되어 있기 때문에 작업하기가 더 쉬울 것 같지만 SQLite 데이터베이스에 제공할 수 있는 명령문을 만들 수 있다면 그것도 좋을 것입니다.
답변1
이 Perl 스크립트가 그 일을 해낼 것입니다. 귀하의 예제를 Pastebin에서 테스트했는데 예상대로 작동합니다.
#!/usr/bin/env perl
use strict;
my %k; ## This hash will store the target/replacement pairs
## Read the list of replacements
open(my $r,"$ARGV[0]")||die "Couldn't open replacements list\n";
while(<$r>){
chomp;
my @F=split(/\s+/);
$k{$F[0]}=$F[1]
}
close($r);
$/=undef;
open(my $fh, "$ARGV[1]")||die "Couldn't open input file\n";
while(<$fh>){
## Read the entire file at once
$/=undef;
my @F=split(/\x1f/);
## If this exists in the replacements list
if (defined($k{$F[5]})) {
## Modify the 17th field. This will only replace the first
## occurence. Use 's///g' for all.
$F[16]=~s/$F[5]/$k{$F[5]}/;
## Replace the 6th field
$F[5]=$k{$F[5]};
}
## If it doesn't
else {
## Print the file name to STDERR unless the 5th field
## was empty.
print STDERR "Problematic file: $ARGV[1]\n" unless $F[5]=~/^\s*$/;
}
## print each field separated by '0x1f' again.
print join "\x1f",@F;
}
close($fh);
이를 fixidiocy.pl
귀하의 $HOME
디렉토리와 cd
대상 파일이 포함된 디렉토리에 저장하십시오. 이제 각 파일에서 이를 실행하여 대체 파일의 파일 이름과 경로를 인수로 제공합니다.
for file in *; do
perl ~/fixidiocy.pl /path/to/replacements "$file" > "$file".fixed
done