我有一个包含数百个文件的目录。目录中所有文件的名称也列在Javascript文件中(参见下文)。我想在文本文件中找到目录中不存在的文件名。例如:
% ls ./images/
a.png
c.png
x.png
文件:
{
name: "A",
filename: "a.png"
},
{
name: "X",
filename: "x.png"
}
在这种情况下,输出应为“c.png
”。
我找到了一些能找到字符串的awk
脚本(参见:awk script: check if all words(fields) from one file are contained in another file)。但是在我的情况下,我想找到不匹配的文件列表。
答案 0 :(得分:2)
您可以通过以下命令
完成您想要的任务$ mawk '/filename:/{gsub("\"","",$2);names[$2]}
END{while(("ls ?.png"|getline fnm)>0){
if(!(fnm in names)) print fnm
}}' file.dat
在第一行中,我们扫描数据文件,查找字符串"filename"
,从引号中删除文件名,最后将文件名保存在数组中。
在END
我们对相关ls
命令的输出进行循环,如果当前文件名未保存在数组中,我们将其打印到stdout。
最困难的部分是获得最终for循环的正确语法......
附录
继续原始海报的评论,这里是一个 修改后的脚本版本
$ mawk '/filename:/{gsub("\"","",$2);names[$2]}
END{while(("ls /var/www/html/img/*.png"|getline path)>0){
n = split(path, parts, "/")
fnm = parts[n]
if(!(fnm in names)) print fnm
}}' file.dat
适用于固定目录名称。如果目录名必须是 在运行时给出,请尝试以下
$ extra_png () {
mawk '/filename:/{gsub("\"","",$2);names[$2]}
END{while(("ls '"$2"'/*.png"|getline path)>0){
n = split(path, parts, "/")
fnm = parts[n]
if(!(fnm in names)) print fnm
}}' "$1"
}
$ extra_png data.txt /var/www/html/img
c.png
$
其中第一个命令定义了一个接受as的shell函数 参数数据文件和要扫描的目录。
作为旁注,这个awk
脚本找到了未提及的png文件
数据文件(根据OP请求),知道可能很有趣
如果文件中提到的文件名不存在于
目录。但这可能是另一个问题的主题。
答案 1 :(得分:2)
$ cat tst.awk
BEGIN {
while (ARGC > 2) {
sub(/.*\//,"",ARGV[--ARGC])
targets[ARGV[ARGC]]
delete ARGV[ARGC]
}
}
sub(/.*filename:[[:space:]]*"/,"") && sub(/\"[[:space:]]*$/,"") {
present[$0]
}
END {
print "Present:"
for (file in present) {
if (file in targets) {
print "\t" file
}
}
print "\nAbsent:"
for (file in targets) {
if (! (file in present) ) {
print "\t" file
}
}
}
$ awk -f tst.awk file image/*
Present:
x.png
a.png
Absent:
c.png
请注意,无论您的文件名包含哪些字符(包括空格和双引号),这都会有效,并且不会尝试解析ls
的输出,这总是一个坏主意。
答案 2 :(得分:2)
如果您可以从CPAN安装一些很酷的模块,我会为您的任务提出一个更清洁(IMHO)的脚本:
#!/usr/bin/perl
use strict; use warnings; use 5.010;
use JSON;
use Path::Tiny;
my $json_data = path('images.json')->slurp;
my $data = decode_json( $json_data );
my %files_to_check = map { $_->basename => 0 } path('images')->children;
my @files_in_json = map { $_->{filename} } @$data;
delete @files_to_check{ @files_in_json }; # delete all files we have in JSON
say "$_" for sort keys %files_to_check;
答案 3 :(得分:2)
每当您认为必须在列表中找到或未找到某些内容时,请考虑哈希。哈希是一种索引列表的快捷方式,因为只需查看密钥就可以找到列表中是否存在某些内容。
在本程序的前半部分,我将浏览您的JSON文件,查找文件名并将其存储在名为%files
的哈希中。在下半部分,我将浏览我的png
文件所在的目录,并检查每个文件是否在%files
哈希中。如果某个特定条目不存在,我知道它不在我的JSON文件中。
注意:我本可以使用
use JSON;
来解析我的JSON文件。但是,在本次演示中,我只是在寻找filename
行以保持简单。如果这是一个实际的程序,请使用JSON
模块。
#! /usr/bin/env perl
use strict;
use warnings;
use autodie;
use feature qw(say);
use constant {
FILE_NAME => 'file.txt',
DIR_NAME => 'temp',
};
#
# Build the %files hash
#
open my $fh, "<", FILE_NAME;
my %files;
while ( my $line = <$fh> ) {
chomp $line;
next unless $line =~ /\s+filename:\s+"(.+)"/;
my $file = $1;
$files{$file} = 1;
}
close $fh;
#
# Go through directory looking for entries not in %files
#
opendir my $dh, DIR_NAME;
while ( my $file = readdir $dh ) {
next if $file eq "." or $file eq "..";
if ( not exists $files{$file} ) {
say qq(File "$file" not in list);
}
}
closedir $dh;
答案 4 :(得分:1)
列出数据文件中但使用Perl从目录列表中丢失的文件的一种简单方法是使用目录中的文件测试(或传递完整路径)文件的名称&#34;如果文件不存在&#34;或&#34;除非文件存在&#34;:
perl -nE 'map { say if !-e $_ } m/\"(.*)\"/ if /filename/' data.js
或执行相反的操作(您的示例) - 即从目录列表中打印文件名($fname
)是否可以&#39;可以在从文件列表数据(@m
)创建的名称数组(data.js
)中找到:
perl -nE 'push @m, m/\"(.*)\"/ if /filename/ }{
for $fname (glob "*"){ say $fname if !grep { $_ eq $fname } @m}' data.js
以下是@neuhaus发布的完整脚本变体。区别在于以下方法使用IO::All
来创建IO&#34;对象&#34;从目录'./images/'
作为哈希,然后使用keys
列出文件的名称。我修改了文本文件中的数据以说明grep unless
语句:
# files.pl
use IO::All;
@files = keys %{ io('./images/') } ;
while(<DATA>) {
push @flist, m/\"(.*)\"/ if /filename/ ;
}
for $fname ( @flist) {print $fname unless grep { $_ eq $name } @files} ;
__DATA__
{
name: "A",
filename: "a.png"
},
{
name: "X",
filename: "x.png"
},
{
name: "Z",
filename: "z.png"
}
输出(如果在包含perl files.pl
目录的目录中运行./images/
):
% ls ./images/
a.png x.png y.png z.png
% perl files.pl
y.png
在__DATA__
部分(代表data.js
文件)中,文件名被提取到@files
。目录列表中的文件打印unless
可以通过grep
中的@files
找到它们。
这是一个版本作为一个班轮,您的数据在data.js
:
perl -MIO::All -lne 'push @flist, m/\"(.*)\"/ if /filename/ ;
}{ for $name (keys %{ io "./images/" }){ print $name
unless grep { $_ eq $name } @flist }' data.js
更多Unix-ish方法可能会在glob
目录中使用/images/
(警告:有时会出现与某些平台上带空格的文件名有关的问题):
perl -MIO::All -lne 'push @flist, m/\"(.*)\"/ if /filename/ ;
}{ for $name ( glob("*.png") ){ print $name
unless grep { $_ eq $name } @flist }' data.js
的文件和目录句柄
...
opendir(my $dir, ".") || die;
@files = readdir $dir ;
...
答案 5 :(得分:-1)
以下是perl的解决方案:
@list
是包含文件名的数组。
open(my $fh, "<", "input.txt");
my $contents = do { local $/ = <$fh> };
my $string = <$fh>;
close($fh);
foreach my $entry (@list) {
print "$entry is not in file\n" if index($contents, $entry) == -1;
}